#include <pgtypes_timestamp.h>
Go to the source code of this file.
Typedefs | |
typedef long | date |
Functions | |
date * | PGTYPESdate_new (void) |
void | PGTYPESdate_free (date *) |
date | PGTYPESdate_from_asc (char *, char **) |
char * | PGTYPESdate_to_asc (date) |
date | PGTYPESdate_from_timestamp (timestamp) |
void | PGTYPESdate_julmdy (date, int *) |
void | PGTYPESdate_mdyjul (int *, date *) |
int | PGTYPESdate_dayofweek (date) |
void | PGTYPESdate_today (date *) |
int | PGTYPESdate_defmt_asc (date *, const char *, char *) |
int | PGTYPESdate_fmt_asc (date, const char *, char *) |
typedef long date |
Definition at line 8 of file pgtypes_date.h.
int PGTYPESdate_dayofweek | ( | date | ) |
Definition at line 145 of file datetime.c.
References date2j().
Referenced by main(), PGTYPESdate_fmt_asc(), PGTYPEStimestamp_fmt_asc(), and rdayofweek().
{ /* * Sunday: 0 Monday: 1 Tuesday: 2 Wednesday: 3 Thursday: 4 * Friday: 5 Saturday: 6 */ return (int) (dDate + date2j(2000, 1, 1) + 1) % 7; }
int PGTYPESdate_defmt_asc | ( | date * | , | |
const char * | , | |||
char * | ||||
) |
Definition at line 338 of file datetime.c.
References date2j(), free, i, sort-test::list, months, MONTHS_PER_YEAR, NULL, pg_tolower(), pgtypes_alloc(), PGTYPES_DATE_MONTH_MAXLENGTH, pgtypes_date_months, pgtypes_strdup(), tm, and pg_tm::tm_year.
Referenced by main(), and rdefmtdate().
{ /* * token[2] = { 4,6 } means that token 2 starts at position 4 and ends at * (including) position 6 */ int token[3][2]; int token_values[3] = {-1, -1, -1}; char *fmt_token_order; char *fmt_ystart, *fmt_mstart, *fmt_dstart; unsigned int i; int reading_digit; int token_count; char *str_copy; struct tm tm; tm.tm_year = tm.tm_mon = tm.tm_mday = 0; /* keep compiler quiet */ if (!d || !str || !fmt) { errno = PGTYPES_DATE_ERR_EARGS; return -1; } /* analyze the fmt string */ fmt_ystart = strstr(fmt, "yy"); fmt_mstart = strstr(fmt, "mm"); fmt_dstart = strstr(fmt, "dd"); if (!fmt_ystart || !fmt_mstart || !fmt_dstart) { errno = PGTYPES_DATE_ERR_EARGS; return -1; } if (fmt_ystart < fmt_mstart) { /* y m */ if (fmt_dstart < fmt_ystart) { /* d y m */ fmt_token_order = "dym"; } else if (fmt_dstart > fmt_mstart) { /* y m d */ fmt_token_order = "ymd"; } else { /* y d m */ fmt_token_order = "ydm"; } } else { /* fmt_ystart > fmt_mstart */ /* m y */ if (fmt_dstart < fmt_mstart) { /* d m y */ fmt_token_order = "dmy"; } else if (fmt_dstart > fmt_ystart) { /* m y d */ fmt_token_order = "myd"; } else { /* m d y */ fmt_token_order = "mdy"; } } /* * handle the special cases where there is no delimiter between the * digits. If we see this: * * only digits, 6 or 8 bytes then it might be ddmmyy and ddmmyyyy (or * similar) * * we reduce it to a string with delimiters and continue processing */ /* check if we have only digits */ reading_digit = 1; for (i = 0; str[i]; i++) { if (!isdigit((unsigned char) str[i])) { reading_digit = 0; break; } } if (reading_digit) { int frag_length[3]; int target_pos; i = strlen(str); if (i != 8 && i != 6) { errno = PGTYPES_DATE_ERR_ENOSHORTDATE; return -1; } /* okay, this really is the special case */ /* * as long as the string, one additional byte for the terminator and 2 * for the delimiters between the 3 fiedls */ str_copy = pgtypes_alloc(strlen(str) + 1 + 2); if (!str_copy) return -1; /* determine length of the fragments */ if (i == 6) { frag_length[0] = 2; frag_length[1] = 2; frag_length[2] = 2; } else { if (fmt_token_order[0] == 'y') { frag_length[0] = 4; frag_length[1] = 2; frag_length[2] = 2; } else if (fmt_token_order[1] == 'y') { frag_length[0] = 2; frag_length[1] = 4; frag_length[2] = 2; } else { frag_length[0] = 2; frag_length[1] = 2; frag_length[2] = 4; } } target_pos = 0; /* * XXX: Here we could calculate the positions of the tokens and save * the for loop down there where we again check with isdigit() for * digits. */ for (i = 0; i < 3; i++) { int start_pos = 0; if (i >= 1) start_pos += frag_length[0]; if (i == 2) start_pos += frag_length[1]; strncpy(str_copy + target_pos, str + start_pos, frag_length[i]); target_pos += frag_length[i]; if (i != 2) { str_copy[target_pos] = ' '; target_pos++; } } str_copy[target_pos] = '\0'; } else { str_copy = pgtypes_strdup(str); if (!str_copy) return -1; /* convert the whole string to lower case */ for (i = 0; str_copy[i]; i++) str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]); } /* look for numerical tokens */ reading_digit = 0; token_count = 0; for (i = 0; i < strlen(str_copy); i++) { if (!isdigit((unsigned char) str_copy[i]) && reading_digit) { /* the token is finished */ token[token_count][1] = i - 1; reading_digit = 0; token_count++; } else if (isdigit((unsigned char) str_copy[i]) && !reading_digit) { /* we have found a token */ token[token_count][0] = i; reading_digit = 1; } } /* * we're at the end of the input string, but maybe we are still reading a * number... */ if (reading_digit) { token[token_count][1] = i - 1; token_count++; } if (token_count < 2) { /* * not all tokens found, no way to find 2 missing tokens with string * matches */ free(str_copy); errno = PGTYPES_DATE_ERR_ENOSHORTDATE; return -1; } if (token_count != 3) { /* * not all tokens found but we may find another one with string * matches by testing for the months names and months abbreviations */ char *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH); char *start_pos; int j; int offset; int found = 0; char **list; if (!month_lower_tmp) { /* free variables we alloc'ed before */ free(str_copy); return -1; } list = pgtypes_date_months; for (i = 0; list[i]; i++) { for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++) { month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]); if (!month_lower_tmp[j]) { /* properly terminated */ break; } } if ((start_pos = strstr(str_copy, month_lower_tmp))) { offset = start_pos - str_copy; /* * sort the new token into the numeric tokens, shift them if * necessary */ if (offset < token[0][0]) { token[2][0] = token[1][0]; token[2][1] = token[1][1]; token[1][0] = token[0][0]; token[1][1] = token[0][1]; token_count = 0; } else if (offset < token[1][0]) { token[2][0] = token[1][0]; token[2][1] = token[1][1]; token_count = 1; } else token_count = 2; token[token_count][0] = offset; token[token_count][1] = offset + strlen(month_lower_tmp) - 1; /* * the value is the index of the month in the array of months * + 1 (January is month 0) */ token_values[token_count] = i + 1; found = 1; break; } /* * evil[tm] hack: if we read the pgtypes_date_months and haven't * found a match, reset list to point to pgtypes_date_months_short * and reset the counter variable i */ if (list == pgtypes_date_months) { if (list[i + 1] == NULL) { list = months; i = -1; } } } if (!found) { free(month_lower_tmp); free(str_copy); errno = PGTYPES_DATE_ERR_ENOTDMY; return -1; } /* * here we found a month. token[token_count] and * token_values[token_count] reflect the month's details. * * only the month can be specified with a literal. Here we can do a * quick check if the month is at the right position according to the * format string because we can check if the token that we expect to * be the month is at the position of the only token that already has * a value. If we wouldn't check here we could say "December 4 1990" * with a fmt string of "dd mm yy" for 12 April 1990. */ if (fmt_token_order[token_count] != 'm') { /* deal with the error later on */ token_values[token_count] = -1; } free(month_lower_tmp); } /* terminate the tokens with ASCII-0 and get their values */ for (i = 0; i < 3; i++) { *(str_copy + token[i][1] + 1) = '\0'; /* A month already has a value set, check for token_value == -1 */ if (token_values[i] == -1) { errno = 0; token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10); /* strtol sets errno in case of an error */ if (errno) token_values[i] = -1; } if (fmt_token_order[i] == 'd') tm.tm_mday = token_values[i]; else if (fmt_token_order[i] == 'm') tm.tm_mon = token_values[i]; else if (fmt_token_order[i] == 'y') tm.tm_year = token_values[i]; } free(str_copy); if (tm.tm_mday < 1 || tm.tm_mday > 31) { errno = PGTYPES_DATE_BAD_DAY; return -1; } if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR) { errno = PGTYPES_DATE_BAD_MONTH; return -1; } if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon == 11)) { errno = PGTYPES_DATE_BAD_DAY; return -1; } if (tm.tm_mon == 2 && tm.tm_mday > 29) { errno = PGTYPES_DATE_BAD_DAY; return -1; } *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1); return 0; }
int PGTYPESdate_fmt_asc | ( | date | , | |
const char * | , | |||
char * | ||||
) |
Definition at line 176 of file datetime.c.
References date2j(), format, free, i, j2date(), months, NULL, pgtypes_alloc(), PGTYPES_DATE_NUM_MAX_DIGITS, pgtypes_date_weekdays_short, PGTYPES_FMTDATE_DAY_DIGITS_LZ, PGTYPES_FMTDATE_DOW_LITERAL_SHORT, PGTYPES_FMTDATE_MONTH_DIGITS_LZ, PGTYPES_FMTDATE_MONTH_LITERAL_SHORT, PGTYPES_FMTDATE_YEAR_DIGITS_LONG, PGTYPES_FMTDATE_YEAR_DIGITS_SHORT, PGTYPES_TYPE_STRING_CONSTANT, PGTYPES_TYPE_STRING_MALLOCED, PGTYPES_TYPE_UINT, PGTYPES_TYPE_UINT_2_LZ, PGTYPES_TYPE_UINT_4_LZ, PGTYPESdate_dayofweek(), snprintf(), un_fmt_comb::str_val, tm, and un_fmt_comb::uint_val.
Referenced by main(), and rfmtdate().
{ static struct { char *format; int component; } mapping[] = { /* * format items have to be sorted according to their length, since the * first pattern that matches gets replaced by its value */ { "ddd", PGTYPES_FMTDATE_DOW_LITERAL_SHORT }, { "dd", PGTYPES_FMTDATE_DAY_DIGITS_LZ }, { "mmm", PGTYPES_FMTDATE_MONTH_LITERAL_SHORT }, { "mm", PGTYPES_FMTDATE_MONTH_DIGITS_LZ }, { "yyyy", PGTYPES_FMTDATE_YEAR_DIGITS_LONG }, { "yy", PGTYPES_FMTDATE_YEAR_DIGITS_SHORT }, { NULL, 0 } }; union un_fmt_comb replace_val; int replace_type; int i; int dow; char *start_pattern; struct tm tm; /* copy the string over */ strcpy(outbuf, fmtstring); /* get the date */ j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); dow = PGTYPESdate_dayofweek(dDate); for (i = 0; mapping[i].format != NULL; i++) { while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL) { switch (mapping[i].component) { case PGTYPES_FMTDATE_DOW_LITERAL_SHORT: replace_val.str_val = pgtypes_date_weekdays_short[dow]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case PGTYPES_FMTDATE_DAY_DIGITS_LZ: replace_val.uint_val = tm.tm_mday; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT: replace_val.str_val = months[tm.tm_mon - 1]; replace_type = PGTYPES_TYPE_STRING_CONSTANT; break; case PGTYPES_FMTDATE_MONTH_DIGITS_LZ: replace_val.uint_val = tm.tm_mon; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; case PGTYPES_FMTDATE_YEAR_DIGITS_LONG: replace_val.uint_val = tm.tm_year; replace_type = PGTYPES_TYPE_UINT_4_LZ; break; case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT: replace_val.uint_val = tm.tm_year % 100; replace_type = PGTYPES_TYPE_UINT_2_LZ; break; default: /* * should not happen, set something anyway */ replace_val.str_val = " "; replace_type = PGTYPES_TYPE_STRING_CONSTANT; } switch (replace_type) { case PGTYPES_TYPE_STRING_MALLOCED: case PGTYPES_TYPE_STRING_CONSTANT: strncpy(start_pattern, replace_val.str_val, strlen(replace_val.str_val)); if (replace_type == PGTYPES_TYPE_STRING_MALLOCED) free(replace_val.str_val); break; case PGTYPES_TYPE_UINT: { char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) return -1; snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, "%u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } break; case PGTYPES_TYPE_UINT_2_LZ: { char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) return -1; snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, "%02u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } break; case PGTYPES_TYPE_UINT_4_LZ: { char *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); if (!t) return -1; snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, "%04u", replace_val.uint_val); strncpy(start_pattern, t, strlen(t)); free(t); } break; default: /* * doesn't happen (we set replace_type to * PGTYPES_TYPE_STRING_CONSTANT in case of an error above) */ break; } } } return 0; }
void PGTYPESdate_free | ( | date * | ) |
date PGTYPESdate_from_asc | ( | char * | , | |
char ** | ||||
) |
Definition at line 53 of file datetime.c.
References date2j(), DecodeDateTime(), DTK_DATE, DTK_EPOCH, GetEpochTime(), MAXDATELEN, ParseDateTime(), and tm.
Referenced by ecpg_get_data(), and main().
{ date dDate; fsec_t fsec; struct tm tt, *tm = &tt; int dtype; int nf; char *field[MAXDATEFIELDS]; int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + 1]; char *realptr; char **ptr = (endptr != NULL) ? endptr : &realptr; bool EuroDates = FALSE; errno = 0; if (strlen(str) >= sizeof(lowstr)) { errno = PGTYPES_DATE_BAD_DATE; return INT_MIN; } if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 || DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0) { errno = PGTYPES_DATE_BAD_DATE; return INT_MIN; } switch (dtype) { case DTK_DATE: break; case DTK_EPOCH: if (GetEpochTime(tm) < 0) { errno = PGTYPES_DATE_BAD_DATE; return INT_MIN; } break; default: errno = PGTYPES_DATE_BAD_DATE; return INT_MIN; } dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1)); return dDate; }
Definition at line 32 of file datetime.c.
References SECS_PER_DAY, and TIMESTAMP_NOT_FINITE.
Referenced by main(), and PGTYPEStimestamp_fmt_asc().
{ date dDate; dDate = 0; /* suppress compiler warning */ if (!TIMESTAMP_NOT_FINITE(dt)) { #ifdef HAVE_INT64_TIMESTAMP /* Microseconds to days */ dDate = (dt / USECS_PER_DAY); #else /* Seconds to days */ dDate = (dt / (double) SECS_PER_DAY); #endif } return dDate; }
void PGTYPESdate_julmdy | ( | date | , | |
int * | ||||
) |
void PGTYPESdate_mdyjul | ( | int * | , | |
date * | ||||
) |
date* PGTYPESdate_new | ( | void | ) |
Definition at line 16 of file datetime.c.
References pgtypes_alloc().
Referenced by main().
{ date *result; result = (date *) pgtypes_alloc(sizeof(date)); /* result can be NULL if we run out of memory */ return result; }
char* PGTYPESdate_to_asc | ( | date | ) |
Definition at line 108 of file datetime.c.
References buf, date2j(), DateStyle, EncodeDateOnly(), j2date(), MAXDATELEN, pgtypes_strdup(), and tm.
Referenced by ecpg_store_input(), main(), and rdatestr().
{ struct tm tt, *tm = &tt; char buf[MAXDATELEN + 1]; int DateStyle = 1; bool EuroDates = FALSE; j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); EncodeDateOnly(tm, DateStyle, buf, EuroDates); return pgtypes_strdup(buf); }
void PGTYPESdate_today | ( | date * | ) |
Definition at line 155 of file datetime.c.
References date2j(), GetCurrentDateTime(), and tm.
Referenced by rtoday().
{ struct tm ts; GetCurrentDateTime(&ts); if (errno == 0) *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1); return; }