#include "postgres_fe.h"
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "extern.h"
#include "dt.h"
#include "pgtypes_timestamp.h"
Go to the source code of this file.
Defines | |
#define | ABS_SIGNBIT ((char) 0200) |
#define | POS(n) (n) |
#define | NEG(n) ((n)|ABS_SIGNBIT) |
#define | FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 15) |
#define | VALMASK ((char) 0177) |
#define | SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c)) |
Typedefs | |
typedef long | AbsoluteTime |
Functions | |
static datetkn * | datebsearch (char *key, datetkn *base, unsigned int nel) |
int | DecodeUnits (int field, char *lowtoken, int *val) |
int | date2j (int y, int m, int d) |
void | j2date (int jd, int *year, int *month, int *day) |
static int | DecodeSpecial (int field, char *lowtoken, int *val) |
int | EncodeDateOnly (struct tm *tm, int style, char *str, bool EuroDates) |
void | TrimTrailingZeros (char *str) |
int | EncodeDateTime (struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates) |
int | GetEpochTime (struct tm *tm) |
static void | abstime2tm (AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn) |
void | GetCurrentDateTime (struct tm *tm) |
void | dt2time (double jd, int *hour, int *min, int *sec, fsec_t *fsec) |
static int | DecodeNumberField (int len, char *str, int fmask, int *tmask, struct tm *tm, fsec_t *fsec, int *is2digits) |
static int | DecodeNumber (int flen, char *str, int fmask, int *tmask, struct tm *tm, fsec_t *fsec, int *is2digits, bool EuroDates) |
static int | DecodeDate (char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates) |
int | DecodeTime (char *str, int *tmask, struct tm *tm, fsec_t *fsec) |
static int | DecodeTimezone (char *str, int *tzp) |
static int | DecodePosixTimezone (char *str, int *tzp) |
int | ParseDateTime (char *timestr, char *lowstr, char **field, int *ftype, int *numfields, char **endstr) |
int | DecodeDateTime (char **field, int *ftype, int nf, int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates) |
static char * | find_end_token (char *str, char *fmt) |
static int | pgtypes_defmt_scan (union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt) |
int | PGTYPEStimestamp_defmt_scan (char **, char *, timestamp *, int *, int *, int *, int *, int *, int *, int *) |
Variables | |
int | day_tab [2][13] |
static datetkn | datetktbl [] |
static datetkn | deltatktbl [] |
static const unsigned int | szdatetktbl = lengthof(datetktbl) |
static const unsigned int | szdeltatktbl = lengthof(deltatktbl) |
static datetkn * | datecache [MAXDATEFIELDS] = {NULL} |
static datetkn * | deltacache [MAXDATEFIELDS] = {NULL} |
char * | months [] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL} |
char * | days [] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL} |
char * | pgtypes_date_weekdays_short [] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL} |
char * | pgtypes_date_months [] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL} |
#define ABS_SIGNBIT ((char) 0200) |
Definition at line 19 of file dt_common.c.
#define FROMVAL | ( | tp | ) | (-SIGNEDCHAR((tp)->value) * 15) |
Definition at line 22 of file dt_common.c.
Referenced by DecodeSpecial(), and DecodeUnits().
#define NEG | ( | n | ) | ((n)|ABS_SIGNBIT) |
Definition at line 21 of file dt_common.c.
#define POS | ( | n | ) | (n) |
Definition at line 20 of file dt_common.c.
Definition at line 24 of file dt_common.c.
#define VALMASK ((char) 0177) |
Definition at line 23 of file dt_common.c.
typedef long AbsoluteTime |
Definition at line 17 of file dt_common.c.
static void abstime2tm | ( | AbsoluteTime | _time, | |
int * | tzp, | |||
struct tm * | tm, | |||
char ** | tzn | |||
) | [static] |
Definition at line 1035 of file dt_common.c.
References MAXTZLEN, NULL, SECS_PER_HOUR, StrNCpy, TIMEZONE_GLOBAL, and TZNAME_GLOBAL.
{ time_t time = (time_t) _time; struct tm *tx; errno = 0; if (tzp != NULL) tx = localtime((time_t *) &time); else tx = gmtime((time_t *) &time); if (!tx) { errno = PGTYPES_TS_BAD_TIMESTAMP; return; } tm->tm_year = tx->tm_year + 1900; tm->tm_mon = tx->tm_mon + 1; tm->tm_mday = tx->tm_mday; tm->tm_hour = tx->tm_hour; tm->tm_min = tx->tm_min; tm->tm_sec = tx->tm_sec; tm->tm_isdst = tx->tm_isdst; #if defined(HAVE_TM_ZONE) tm->tm_gmtoff = tx->tm_gmtoff; tm->tm_zone = tx->tm_zone; if (tzp != NULL) { /* * We have a brute force time zone per SQL99? Then use it without * change since we have already rotated to the time zone. */ *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */ /* * FreeBSD man pages indicate that this should work - tgl 97/04/23 */ if (tzn != NULL) { /* * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it * contains an error message, which doesn't fit in the buffer */ StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1); if (strlen(tm->tm_zone) > MAXTZLEN) tm->tm_isdst = -1; } } else tm->tm_isdst = -1; #elif defined(HAVE_INT_TIMEZONE) if (tzp != NULL) { *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL; if (tzn != NULL) { /* * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it * contains an error message, which doesn't fit in the buffer */ StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1); if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN) tm->tm_isdst = -1; } } else tm->tm_isdst = -1; #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ if (tzp != NULL) { /* default to UTC */ *tzp = 0; if (tzn != NULL) *tzn = NULL; } else tm->tm_isdst = -1; #endif }
int date2j | ( | int | y, | |
int | m, | |||
int | d | |||
) |
Definition at line 592 of file dt_common.c.
{ int julian; int century; if (m > 2) { m += 1; y += 4800; } else { m += 13; y += 4799; } century = y / 100; julian = y * 365 - 32167; julian += y / 4 - century + century / 4; julian += 7834 * m / 256 + d; return julian; } /* date2j() */
Definition at line 513 of file dt_common.c.
References TOKMAXLEN.
Referenced by DecodeSpecial(), and DecodeUnits().
{ if (nel > 0) { datetkn *last = base + nel - 1, *position; int result; while (last >= base) { position = base + ((last - base) >> 1); result = key[0] - position->token[0]; if (result == 0) { result = strncmp(key, position->token, TOKMAXLEN); if (result == 0) return position; } if (result < 0) last = position - 1; else base = position + 1; } } return NULL; }
static int DecodeDate | ( | char * | str, | |
int | fmask, | |||
int * | tmask, | |||
struct tm * | tm, | |||
bool | EuroDates | |||
) | [static] |
Definition at line 1378 of file dt_common.c.
References ADBC, DecodeNumber(), DecodeSpecial(), DOY, DTK_M, i, IGNORE_DTF, MAXDATEFIELDS, MONTH, NULL, TZ, and val.
Referenced by DecodeDateTime().
{ fsec_t fsec; int nf = 0; int i, len; int bc = FALSE; int is2digits = FALSE; int type, val, dmask = 0; char *field[MAXDATEFIELDS]; /* parse this string... */ while (*str != '\0' && nf < MAXDATEFIELDS) { /* skip field separators */ while (!isalnum((unsigned char) *str)) str++; field[nf] = str; if (isdigit((unsigned char) *str)) { while (isdigit((unsigned char) *str)) str++; } else if (isalpha((unsigned char) *str)) { while (isalpha((unsigned char) *str)) str++; } /* Just get rid of any non-digit, non-alpha characters... */ if (*str != '\0') *str++ = '\0'; nf++; } #if 0 /* don't allow too many fields */ if (nf > 3) return -1; #endif *tmask = 0; /* look first for text fields, since that will be unambiguous month */ for (i = 0; i < nf; i++) { if (isalpha((unsigned char) *field[i])) { type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) continue; dmask = DTK_M(type); switch (type) { case MONTH: tm->tm_mon = val; break; case ADBC: bc = (val == BC); break; default: return -1; } if (fmask & dmask) return -1; fmask |= dmask; *tmask |= dmask; /* mark this field as being completed */ field[i] = NULL; } } /* now pick up remaining numeric fields */ for (i = 0; i < nf; i++) { if (field[i] == NULL) continue; if ((len = strlen(field[i])) <= 0) return -1; if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0) return -1; if (fmask & dmask) return -1; fmask |= dmask; *tmask |= dmask; } if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) return -1; /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ if (bc) { if (tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); else return -1; } else if (is2digits) { if (tm->tm_year < 70) tm->tm_year += 2000; else if (tm->tm_year < 100) tm->tm_year += 1900; } return 0; } /* DecodeDate() */
int DecodeDateTime | ( | char ** | field, | |
int * | ftype, | |||
int | nf, | |||
int * | dtype, | |||
struct tm * | tm, | |||
fsec_t * | fsec, | |||
bool | EuroDates | |||
) |
Definition at line 1852 of file dt_common.c.
References ADBC, AM, AMPM, date2j(), DAY, day_tab, DecodeDate(), DecodeNumber(), DecodeNumberField(), DecodePosixTimezone(), DecodeSpecial(), DecodeTime(), DecodeTimezone(), DOW, dt2time(), DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_HOUR, DTK_JULIAN, DTK_M, DTK_MINUTE, DTK_MONTH, DTK_NOW, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TIME_M, DTK_TODAY, DTK_TOMORROW, DTK_TZ, DTK_YEAR, DTK_YESTERDAY, DTK_ZULU, DTZ, DTZMOD, GetCurrentDateTime(), HOUR, HR24, i, IGNORE_DTF, isleap, ISOTIME, j2date(), MINUTE, MONTH, NULL, PM, RESERV, SECOND, SECS_PER_DAY, TZ, UNITS, USECS_PER_DAY, val, and YEAR.
{ int fmask = 0, tmask, type; int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */ int i; int val; int mer = HR24; int haveTextMonth = FALSE; int is2digits = FALSE; int bc = FALSE; int t = 0; int *tzp = &t; /*** * We'll insist on at least all of the date fields, but initialize the * remaining fields in case they are not set later... ***/ *dtype = DTK_DATE; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; *fsec = 0; /* don't know daylight savings time status apriori */ tm->tm_isdst = -1; if (tzp != NULL) *tzp = 0; for (i = 0; i < nf; i++) { switch (ftype[i]) { case DTK_DATE: /*** * Integral julian day with attached time zone? * All other forms with JD will be separated into * distinct fields, so we handle just this case here. ***/ if (ptype == DTK_JULIAN) { char *cp; int val; if (tzp == NULL) return -1; val = strtol(field[i], &cp, 10); if (*cp != '-') return -1; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); /* Get the time zone from the end of the string */ if (DecodeTimezone(cp, tzp) != 0) return -1; tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ); ptype = 0; break; } /*** * Already have a date? Then this might be a POSIX time * zone with an embedded dash (e.g. "PST-3" == "EST") or * a run-together time with trailing time zone (e.g. hhmmss-zz). * - thomas 2001-12-25 ***/ else if (((fmask & DTK_DATE_M) == DTK_DATE_M) || (ptype != 0)) { /* No time zone accepted? Then quit... */ if (tzp == NULL) return -1; if (isdigit((unsigned char) *field[i]) || ptype != 0) { char *cp; if (ptype != 0) { /* Sanity check; should not fail this test */ if (ptype != DTK_TIME) return -1; ptype = 0; } /* * Starts with a digit but we already have a time * field? Then we are in trouble with a date and time * already... */ if ((fmask & DTK_TIME_M) == DTK_TIME_M) return -1; if ((cp = strchr(field[i], '-')) == NULL) return -1; /* Get the time zone from the end of the string */ if (DecodeTimezone(cp, tzp) != 0) return -1; *cp = '\0'; /* * Then read the rest of the field as a concatenated * time */ if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask, &tmask, tm, fsec, &is2digits)) < 0) return -1; /* * modify tmask after returning from * DecodeNumberField() */ tmask |= DTK_M(TZ); } else { if (DecodePosixTimezone(field[i], tzp) != 0) return -1; ftype[i] = DTK_TZ; tmask = DTK_M(TZ); } } else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0) return -1; break; case DTK_TIME: if (DecodeTime(field[i], &tmask, tm, fsec) != 0) return -1; /* * Check upper limit on hours; other limits checked in * DecodeTime() */ /* test for > 24:00:00 */ if (tm->tm_hour > 24 || (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0))) return -1; break; case DTK_TZ: { int tz; if (tzp == NULL) return -1; if (DecodeTimezone(field[i], &tz) != 0) return -1; /* * Already have a time zone? Then maybe this is the second * field of a POSIX time: EST+3 (equivalent to PST) */ if (i > 0 && (fmask & DTK_M(TZ)) != 0 && ftype[i - 1] == DTK_TZ && isalpha((unsigned char) *field[i - 1])) { *tzp -= tz; tmask = 0; } else { *tzp = tz; tmask = DTK_M(TZ); } } break; case DTK_NUMBER: /* * Was this an "ISO date" with embedded field labels? An * example is "y2001m02d04" - thomas 2001-02-04 */ if (ptype != 0) { char *cp; int val; val = strtol(field[i], &cp, 10); /* * only a few kinds are allowed to have an embedded * decimal */ if (*cp == '.') switch (ptype) { case DTK_JULIAN: case DTK_TIME: case DTK_SECOND: break; default: return 1; break; } else if (*cp != '\0') return -1; switch (ptype) { case DTK_YEAR: tm->tm_year = val; tmask = DTK_M(YEAR); break; case DTK_MONTH: /* * already have a month and hour? then assume * minutes */ if ((fmask & DTK_M(MONTH)) != 0 && (fmask & DTK_M(HOUR)) != 0) { tm->tm_min = val; tmask = DTK_M(MINUTE); } else { tm->tm_mon = val; tmask = DTK_M(MONTH); } break; case DTK_DAY: tm->tm_mday = val; tmask = DTK_M(DAY); break; case DTK_HOUR: tm->tm_hour = val; tmask = DTK_M(HOUR); break; case DTK_MINUTE: tm->tm_min = val; tmask = DTK_M(MINUTE); break; case DTK_SECOND: tm->tm_sec = val; tmask = DTK_M(SECOND); if (*cp == '.') { double frac; frac = strtod(cp, &cp); if (*cp != '\0') return -1; #ifdef HAVE_INT64_TIMESTAMP *fsec = frac * 1000000; #else *fsec = frac; #endif } break; case DTK_TZ: tmask = DTK_M(TZ); if (DecodeTimezone(field[i], tzp) != 0) return -1; break; case DTK_JULIAN: /*** * previous field was a label for "julian date"? ***/ tmask = DTK_DATE_M; j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); /* fractional Julian Day? */ if (*cp == '.') { double time; time = strtod(cp, &cp); if (*cp != '\0') return -1; tmask |= DTK_TIME_M; #ifdef HAVE_INT64_TIMESTAMP dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); #else dt2time((time * SECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); #endif } break; case DTK_TIME: /* previous field was "t" for ISO time */ if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M), &tmask, tm, fsec, &is2digits)) < 0) return -1; if (tmask != DTK_TIME_M) return -1; break; default: return -1; break; } ptype = 0; *dtype = DTK_DATE; } else { char *cp; int flen; flen = strlen(field[i]); cp = strchr(field[i], '.'); /* Embedded decimal and no date yet? */ if (cp != NULL && !(fmask & DTK_DATE_M)) { if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0) return -1; } /* embedded decimal and several digits before? */ else if (cp != NULL && flen - strlen(cp) > 2) { /* * Interpret as a concatenated date or time Set the * type field to allow decoding other fields later. * Example: 20011223 or 040506 */ if ((ftype[i] = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits)) < 0) return -1; } else if (flen > 4) { if ((ftype[i] = DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits)) < 0) return -1; } /* otherwise it is a single date/time field... */ else if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits, EuroDates) != 0) return -1; } break; case DTK_STRING: case DTK_SPECIAL: type = DecodeSpecial(i, field[i], &val); if (type == IGNORE_DTF) continue; tmask = DTK_M(type); switch (type) { case RESERV: switch (val) { case DTK_NOW: tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ)); *dtype = DTK_DATE; GetCurrentDateTime(tm); break; case DTK_YESTERDAY: tmask = DTK_DATE_M; *dtype = DTK_DATE; GetCurrentDateTime(tm); j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; break; case DTK_TODAY: tmask = DTK_DATE_M; *dtype = DTK_DATE; GetCurrentDateTime(tm); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; break; case DTK_TOMORROW: tmask = DTK_DATE_M; *dtype = DTK_DATE; GetCurrentDateTime(tm); j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; break; case DTK_ZULU: tmask = (DTK_TIME_M | DTK_M(TZ)); *dtype = DTK_DATE; tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; if (tzp != NULL) *tzp = 0; break; default: *dtype = val; } break; case MONTH: /* * already have a (numeric) month? then see if we can * substitute... */ if ((fmask & DTK_M(MONTH)) && !haveTextMonth && !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31) { tm->tm_mday = tm->tm_mon; tmask = DTK_M(DAY); } haveTextMonth = TRUE; tm->tm_mon = val; break; case DTZMOD: /* * daylight savings time modifier (solves "MET DST" * syntax) */ tmask |= DTK_M(DTZ); tm->tm_isdst = 1; if (tzp == NULL) return -1; *tzp += val * MINS_PER_HOUR; break; case DTZ: /* * set mask for TZ here _or_ check for DTZ later when * getting default timezone */ tmask |= DTK_M(TZ); tm->tm_isdst = 1; if (tzp == NULL) return -1; *tzp = val * MINS_PER_HOUR; ftype[i] = DTK_TZ; break; case TZ: tm->tm_isdst = 0; if (tzp == NULL) return -1; *tzp = val * MINS_PER_HOUR; ftype[i] = DTK_TZ; break; case IGNORE_DTF: break; case AMPM: mer = val; break; case ADBC: bc = (val == BC); break; case DOW: tm->tm_wday = val; break; case UNITS: tmask = 0; ptype = val; break; case ISOTIME: /* * This is a filler field "t" indicating that the next * field is time. Try to verify that this is sensible. */ tmask = 0; /* No preceding date? Then quit... */ if ((fmask & DTK_DATE_M) != DTK_DATE_M) return -1; /*** * We will need one of the following fields: * DTK_NUMBER should be hhmmss.fff * DTK_TIME should be hh:mm:ss.fff * DTK_DATE should be hhmmss-zz ***/ if (i >= nf - 1 || (ftype[i + 1] != DTK_NUMBER && ftype[i + 1] != DTK_TIME && ftype[i + 1] != DTK_DATE)) return -1; ptype = val; break; default: return -1; } break; default: return -1; } if (tmask & fmask) return -1; fmask |= tmask; } /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ if (bc) { if (tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); else return -1; } else if (is2digits) { if (tm->tm_year < 70) tm->tm_year += 2000; else if (tm->tm_year < 100) tm->tm_year += 1900; } if (mer != HR24 && tm->tm_hour > 12) return -1; if (mer == AM && tm->tm_hour == 12) tm->tm_hour = 0; else if (mer == PM && tm->tm_hour != 12) tm->tm_hour += 12; /* do additional checking for full date specs... */ if (*dtype == DTK_DATE) { if ((fmask & DTK_DATE_M) != DTK_DATE_M) return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1; /* * check for valid day of month, now that we know for sure the month * and year... */ if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) return -1; /* * backend tried to find local timezone here but we don't use the * result afterwards anyway so we only check for this error: daylight * savings time modifier but no standard timezone? */ if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD))) return -1; } return 0; } /* DecodeDateTime() */
static int DecodeNumber | ( | int | flen, | |
char * | str, | |||
int | fmask, | |||
int * | tmask, | |||
struct tm * | tm, | |||
fsec_t * | fsec, | |||
int * | is2digits, | |||
bool | EuroDates | |||
) | [static] |
Definition at line 1269 of file dt_common.c.
References date2j(), DAY, DecodeNumberField(), DOY, DTK_DATE_M, DTK_M, j2date(), MONTH, MONTHS_PER_YEAR, val, and YEAR.
Referenced by DecodeDate(), and DecodeDateTime().
{ int val; char *cp; *tmask = 0; val = strtol(str, &cp, 10); if (cp == str) return -1; if (*cp == '.') { /* * More than two digits? Then could be a date or a run-together time: * 2001.360 20011225 040506.789 */ if (cp - str > 2) return DecodeNumberField(flen, str, (fmask | DTK_DATE_M), tmask, tm, fsec, is2digits); *fsec = strtod(cp, &cp); if (*cp != '\0') return -1; } else if (*cp != '\0') return -1; /* Special case day of year? */ if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366) { *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY)); tm->tm_yday = val; j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); } /*** * Enough digits to be unequivocal year? Used to test for 4 digits or * more, but we now test first for a three-digit doy so anything * bigger than two digits had better be an explicit year. * - thomas 1999-01-09 * Back to requiring a 4 digit year. We accept a two digit * year farther down. - thomas 2000-03-28 ***/ else if (flen >= 4) { *tmask = DTK_M(YEAR); /* already have a year? then see if we can substitute... */ if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) && tm->tm_year >= 1 && tm->tm_year <= 31) { tm->tm_mday = tm->tm_year; *tmask = DTK_M(DAY); } tm->tm_year = val; } /* already have year? then could be month */ else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR) { *tmask = DTK_M(MONTH); tm->tm_mon = val; } /* no year and EuroDates enabled? then could be day */ else if ((EuroDates || (fmask & DTK_M(MONTH))) && !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) && val >= 1 && val <= 31) { *tmask = DTK_M(DAY); tm->tm_mday = val; } else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR) { *tmask = DTK_M(MONTH); tm->tm_mon = val; } else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31) { *tmask = DTK_M(DAY); tm->tm_mday = val; } /* * Check for 2 or 4 or more digits, but currently we reach here only if * two digits. - thomas 2000-03-28 */ else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2)) { *tmask = DTK_M(YEAR); tm->tm_year = val; /* adjust ONLY if exactly two digits... */ *is2digits = (flen == 2); } else return -1; return 0; } /* DecodeNumber() */
static int DecodeNumberField | ( | int | len, | |
char * | str, | |||
int | fmask, | |||
int * | tmask, | |||
struct tm * | tm, | |||
fsec_t * | fsec, | |||
int * | is2digits | |||
) | [static] |
Definition at line 1162 of file dt_common.c.
References DTK_DATE_M, DTK_TIME_M, MAXDATELEN, and NULL.
Referenced by DecodeDateTime(), and DecodeNumber().
{ char *cp; /* * Have a decimal point? Then this is a date or something with a seconds * field... */ if ((cp = strchr(str, '.')) != NULL) { #ifdef HAVE_INT64_TIMESTAMP char fstr[MAXDATELEN + 1]; /* * OK, we have at most six digits to care about. Let's construct a * string and then do the conversion to an integer. */ strcpy(fstr, (cp + 1)); strcpy(fstr + strlen(fstr), "000000"); *(fstr + 6) = '\0'; *fsec = strtol(fstr, NULL, 10); #else *fsec = strtod(cp, NULL); #endif *cp = '\0'; len = strlen(str); } /* No decimal point and no complete date yet? */ else if ((fmask & DTK_DATE_M) != DTK_DATE_M) { /* yyyymmdd? */ if (len == 8) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 6); *(str + 6) = '\0'; tm->tm_mon = atoi(str + 4); *(str + 4) = '\0'; tm->tm_year = atoi(str + 0); return DTK_DATE; } /* yymmdd? */ else if (len == 6) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 4); *(str + 4) = '\0'; tm->tm_mon = atoi(str + 2); *(str + 2) = '\0'; tm->tm_year = atoi(str + 0); *is2digits = TRUE; return DTK_DATE; } /* yyddd? */ else if (len == 5) { *tmask = DTK_DATE_M; tm->tm_mday = atoi(str + 2); *(str + 2) = '\0'; tm->tm_mon = 1; tm->tm_year = atoi(str + 0); *is2digits = TRUE; return DTK_DATE; } } /* not all time fields are specified? */ if ((fmask & DTK_TIME_M) != DTK_TIME_M) { /* hhmmss */ if (len == 6) { *tmask = DTK_TIME_M; tm->tm_sec = atoi(str + 4); *(str + 4) = '\0'; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } /* hhmm? */ else if (len == 4) { *tmask = DTK_TIME_M; tm->tm_sec = 0; tm->tm_min = atoi(str + 2); *(str + 2) = '\0'; tm->tm_hour = atoi(str + 0); return DTK_TIME; } } return -1; } /* DecodeNumberField() */
static int DecodePosixTimezone | ( | char * | str, | |
int * | tzp | |||
) | [static] |
Definition at line 1621 of file dt_common.c.
References DecodeSpecial(), DecodeTimezone(), DTZ, MAXDATEFIELDS, TZ, and val.
Referenced by DecodeDateTime().
{ int val, tz; int type; char *cp; char delim; cp = str; while (*cp != '\0' && isalpha((unsigned char) *cp)) cp++; if (DecodeTimezone(cp, &tz) != 0) return -1; delim = *cp; *cp = '\0'; type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val); *cp = delim; switch (type) { case DTZ: case TZ: *tzp = (val * MINS_PER_HOUR) - tz; break; default: return -1; } return 0; } /* DecodePosixTimezone() */
static int DecodeSpecial | ( | int | field, | |
char * | lowtoken, | |||
int * | val | |||
) | [static] |
Definition at line 648 of file dt_common.c.
References datebsearch(), DTZ, DTZMOD, FROMVAL, NULL, szdatetktbl, TOKMAXLEN, datetkn::type, TZ, and datetkn::value.
{ int type; datetkn *tp; if (datecache[field] != NULL && strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0) tp = datecache[field]; else { tp = NULL; if (!tp) tp = datebsearch(lowtoken, datetktbl, szdatetktbl); } datecache[field] = tp; if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { type = tp->type; switch (type) { case TZ: case DTZ: case DTZMOD: *val = FROMVAL(tp); break; default: *val = tp->value; break; } } return type; } /* DecodeSpecial() */
Definition at line 1507 of file dt_common.c.
References MAXDATELEN, and USECS_PER_SEC.
{ char *cp; *tmask = DTK_TIME_M; tm->tm_hour = strtol(str, &cp, 10); if (*cp != ':') return -1; str = cp + 1; tm->tm_min = strtol(str, &cp, 10); if (*cp == '\0') { tm->tm_sec = 0; *fsec = 0; } else if (*cp != ':') return -1; else { str = cp + 1; tm->tm_sec = strtol(str, &cp, 10); if (*cp == '\0') *fsec = 0; else if (*cp == '.') { #ifdef HAVE_INT64_TIMESTAMP char fstr[MAXDATELEN + 1]; /* * OK, we have at most six digits to work with. Let's construct a * string and then do the conversion to an integer. */ strncpy(fstr, (cp + 1), 7); strcpy(fstr + strlen(fstr), "000000"); *(fstr + 6) = '\0'; *fsec = strtol(fstr, &cp, 10); #else str = cp; *fsec = strtod(str, &cp); #endif if (*cp != '\0') return -1; } else return -1; } /* do a sanity check */ #ifdef HAVE_INT64_TIMESTAMP if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC) return -1; #else if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= 1) return -1; #endif return 0; } /* DecodeTime() */
static int DecodeTimezone | ( | char * | str, | |
int * | tzp | |||
) | [static] |
Definition at line 1576 of file dt_common.c.
References MINS_PER_HOUR, and SECS_PER_MINUTE.
Referenced by DecodeDateTime(), DecodePosixTimezone(), and PGTYPEStimestamp_defmt_scan().
{ int tz; int hr, min; char *cp; int len; /* assume leading character is "+" or "-" */ hr = strtol(str + 1, &cp, 10); /* explicit delimiter? */ if (*cp == ':') min = strtol(cp + 1, &cp, 10); /* otherwise, might have run things together... */ else if (*cp == '\0' && (len = strlen(str)) > 3) { min = strtol(str + len - 2, &cp, 10); if (min < 0 || min >= 60) return -1; *(str + len - 2) = '\0'; hr = strtol(str + 1, &cp, 10); if (hr < 0 || hr > 13) return -1; } else min = 0; tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE; if (*str == '-') tz = -tz; *tzp = -tz; return *cp != '\0'; } /* DecodeTimezone() */
int DecodeUnits | ( | int | field, | |
char * | lowtoken, | |||
int * | val | |||
) |
Definition at line 545 of file dt_common.c.
References datebsearch(), DTZ, FROMVAL, NULL, szdeltatktbl, datetkn::token, TOKMAXLEN, datetkn::type, TZ, and datetkn::value.
{ int type; datetkn *tp; if (deltacache[field] != NULL && strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0) tp = deltacache[field]; else tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); deltacache[field] = tp; if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { type = tp->type; if (type == TZ || type == DTZ) *val = FROMVAL(tp); else *val = tp->value; } return type; } /* DecodeUnits() */
void dt2time | ( | double | jd, | |
int * | hour, | |||
int * | min, | |||
int * | sec, | |||
fsec_t * | fsec | |||
) |
Definition at line 1128 of file dt_common.c.
{ #ifdef HAVE_INT64_TIMESTAMP int64 time; #else double time; #endif time = jd; #ifdef HAVE_INT64_TIMESTAMP *hour = time / USECS_PER_HOUR; time -= (*hour) * USECS_PER_HOUR; *min = time / USECS_PER_MINUTE; time -= (*min) * USECS_PER_MINUTE; *sec = time / USECS_PER_SEC; *fsec = time - (*sec * USECS_PER_SEC); #else *hour = time / SECS_PER_HOUR; time -= (*hour) * SECS_PER_HOUR; *min = time / SECS_PER_MINUTE; time -= (*min) * SECS_PER_MINUTE; *sec = time; *fsec = time - *sec; #endif } /* dt2time() */
Definition at line 692 of file dt_common.c.
References MONTHS_PER_YEAR, USE_GERMAN_DATES, USE_ISO_DATES, USE_POSTGRES_DATES, and USE_SQL_DATES.
{ if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR) return -1; switch (style) { case USE_ISO_DATES: /* compatible with ISO date formats */ if (tm->tm_year > 0) sprintf(str, "%04d-%02d-%02d", tm->tm_year, tm->tm_mon, tm->tm_mday); else sprintf(str, "%04d-%02d-%02d %s", -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); break; case USE_SQL_DATES: /* compatible with Oracle/Ingres date formats */ if (EuroDates) sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); if (tm->tm_year > 0) sprintf(str + 5, "/%04d", tm->tm_year); else sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC"); break; case USE_GERMAN_DATES: /* German-style date format */ sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); if (tm->tm_year > 0) sprintf(str + 5, ".%04d", tm->tm_year); else sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC"); break; case USE_POSTGRES_DATES: default: /* traditional date-only style for Postgres */ if (EuroDates) sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday); if (tm->tm_year > 0) sprintf(str + 5, "-%04d", tm->tm_year); else sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC"); break; } return TRUE; } /* EncodeDateOnly() */
int EncodeDateTime | ( | struct tm * | tm, | |
fsec_t | fsec, | |||
bool | print_tz, | |||
int | tz, | |||
const char * | tzn, | |||
int | style, | |||
char * | str, | |||
bool | EuroDates | |||
) |
Definition at line 779 of file dt_common.c.
References date2j(), days, MAXTZLEN, MINS_PER_HOUR, months, TrimTrailingZeros(), USE_GERMAN_DATES, USE_ISO_DATES, USE_POSTGRES_DATES, and USE_SQL_DATES.
{ int day, hour, min; /* * Negative tm_isdst means we have no valid time zone translation. */ if (tm->tm_isdst < 0) print_tz = false; switch (style) { case USE_ISO_DATES: /* Compatible with ISO-8601 date formats */ sprintf(str, "%04d-%02d-%02d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */ #ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec); #else if ((fsec != 0) && (tm->tm_year > 0)) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec); #endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (print_tz) { hour = -(tz / SECS_PER_HOUR); min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR; if (min != 0) sprintf(str + strlen(str), "%+03d:%02d", hour, min); else sprintf(str + strlen(str), "%+03d", hour); } break; case USE_SQL_DATES: /* Compatible with Oracle/Ingres date formats */ if (EuroDates) sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); else sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); sprintf(str + 5, "/%04d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */ #ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec); #else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec); #endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); /* * Note: the uses of %.*s in this function would be risky if the * timezone names ever contain non-ASCII characters. However, all * TZ abbreviations in the Olson database are plain ASCII. */ if (print_tz) { if (tzn) sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn); else { hour = -(tz / SECS_PER_HOUR); min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR; if (min != 0) sprintf(str + strlen(str), "%+03d:%02d", hour, min); else sprintf(str + strlen(str), "%+03d", hour); } } break; case USE_GERMAN_DATES: /* German variant on European style */ sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); sprintf(str + 5, ".%04d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */ #ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec); #else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec); #endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (print_tz) { if (tzn) sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn); else { hour = -(tz / SECS_PER_HOUR); min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR; if (min != 0) sprintf(str + strlen(str), "%+03d:%02d", hour, min); else sprintf(str + strlen(str), "%+03d", hour); } } break; case USE_POSTGRES_DATES: default: /* Backward-compatible with traditional Postgres abstime dates */ day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7); strncpy(str, days[tm->tm_wday], 3); strcpy(str + 3, " "); if (EuroDates) sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]); else sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday); sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min); /* * Print fractional seconds if any. The field widths here should * be at least equal to MAX_TIMESTAMP_PRECISION. * * In float mode, don't print fractional seconds before 1 AD, * since it's unlikely there's any precision left ... */ #ifdef HAVE_INT64_TIMESTAMP if (fsec != 0) { sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec); #else if (fsec != 0 && tm->tm_year > 0) { sprintf(str + strlen(str), ":%09.6f", tm->tm_sec + fsec); #endif TrimTrailingZeros(str); } else sprintf(str + strlen(str), ":%02d", tm->tm_sec); sprintf(str + strlen(str), " %04d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); if (print_tz) { if (tzn) sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn); else { /* * We have a time zone, but no string version. Use the * numeric form, but be sure to include a leading space to * avoid formatting something which would be rejected by * the date/time parser later. - thomas 2001-10-19 */ hour = -(tz / SECS_PER_HOUR); min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR; if (min != 0) sprintf(str + strlen(str), " %+03d:%02d", hour, min); else sprintf(str + strlen(str), " %+03d", hour); } } break; } return TRUE; } /* EncodeDateTime() */
static char* find_end_token | ( | char * | str, | |
char * | fmt | |||
) | [static] |
Definition at line 2432 of file dt_common.c.
Referenced by pgtypes_defmt_scan().
{ /* * str: here is28the day12the hour fmt: here is%dthe day%hthe hour * * we extract the 28, we read the percent sign and the type "d" then this * functions gets called as find_end_token("28the day12the hour", "the * day%hthehour") * * fmt points to "the day%hthehour", next_percent points to %hthehour and * we have to find a match for everything between these positions ("the * day"). We look for "the day" in str and know that the pattern we are * about to scan ends where this string starts (right after the "28") * * At the end, *fmt is '\0' and *str isn't. end_position then is * unchanged. */ char *end_position = NULL; char *next_percent, *subst_location = NULL; int scan_offset = 0; char last_char; /* are we at the end? */ if (!*fmt) { end_position = fmt; return end_position; } /* not at the end */ while (fmt[scan_offset] == '%' && fmt[scan_offset + 1]) { /* * there is no delimiter, skip to the next delimiter if we're reading * a number and then something that is not a number "9:15pm", we might * be able to recover with the strtol end pointer. Go for the next * percent sign */ scan_offset += 2; } next_percent = strchr(fmt + scan_offset, '%'); if (next_percent) { /* * we don't want to allocate extra memory, so we temporarily set the * '%' sign to '\0' and call strstr However since we allow whitespace * to float around everything, we have to shorten the pattern until we * reach a non-whitespace character */ subst_location = next_percent; while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset) subst_location--; last_char = *subst_location; *subst_location = '\0'; /* * the haystack is the str and the needle is the original fmt but it * ends at the position where the next percent sign would be */ /* * There is one special case. Imagine: str = " 2", fmt = "%d %...", * since we want to allow blanks as "dynamic" padding we have to * accept this. Now, we are called with a fmt of " %..." and look for * " " in str. We find it at the first position and never read the * 2... */ while (*str == ' ') str++; end_position = strstr(str, fmt + scan_offset); *subst_location = last_char; } else { /* * there is no other percent sign. So everything up to the end has to * match. */ end_position = str + strlen(str); } if (!end_position) { /* * maybe we have the following case: * * str = "4:15am" fmt = "%M:%S %p" * * at this place we could have * * str = "15am" fmt = " %p" * * and have set fmt to " " because overwrote the % sign with a NULL * * In this case where we would have to match a space but can't find * it, set end_position to the end of the string */ if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location) end_position = str + strlen(str); } return end_position; }
void GetCurrentDateTime | ( | struct tm * | tm | ) |
Definition at line 1120 of file dt_common.c.
References abstime2tm(), and NULL.
{ int tz; abstime2tm(time(NULL), &tz, tm, NULL); }
int GetEpochTime | ( | struct tm * | tm | ) |
Definition at line 1012 of file dt_common.c.
References epoch.
void j2date | ( | int | jd, | |
int * | year, | |||
int * | month, | |||
int * | day | |||
) |
Definition at line 617 of file dt_common.c.
References MONTHS_PER_YEAR.
{ unsigned int julian; unsigned int quad; unsigned int extra; int y; julian = jd; julian += 32044; quad = julian / 146097; extra = (julian - quad * 146097) * 4 + 3; julian += 60 + quad * 3 + extra / 146097; quad = julian / 1461; julian -= quad * 1461; y = julian * 4 / 1461; julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123; y += quad * 4; *year = y - 4800; quad = julian * 2141 / 65536; *day = julian - 7834 * quad / 256; *month = (quad + 10) % 12 + 1; return; } /* j2date() */
int ParseDateTime | ( | char * | timestr, | |
char * | lowstr, | |||
char ** | field, | |||
int * | ftype, | |||
int * | numfields, | |||
char ** | endstr | |||
) |
Definition at line 1670 of file dt_common.c.
References DTK_DATE, DTK_NUMBER, MAXDATEFIELDS, and pg_tolower().
{ int nf = 0; char *lp = lowstr; *endstr = timestr; /* outer loop through fields */ while (*(*endstr) != '\0') { field[nf] = lp; /* leading digit? then date or time */ if (isdigit((unsigned char) *(*endstr))) { *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; /* time field? */ if (*(*endstr) == ':') { ftype[nf] = DTK_TIME; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == ':') || (*(*endstr) == '.')) *lp++ = *(*endstr)++; } /* date field? allow embedded text month */ else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.') { /* save delimiting character to use later */ char *dp = (*endstr); *lp++ = *(*endstr)++; /* second field is all digits? then no embedded text month */ if (isdigit((unsigned char) *(*endstr))) { ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; /* * insist that the delimiters match to get a three-field * date. */ if (*(*endstr) == *dp) { ftype[nf] = DTK_DATE; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp)) *lp++ = *(*endstr)++; } } else { ftype[nf] = DTK_DATE; while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp)) *lp++ = pg_tolower((unsigned char) *(*endstr)++); } } /* * otherwise, number only and will determine year, month, day, or * concatenated fields later... */ else ftype[nf] = DTK_NUMBER; } /* Leading decimal point? Then fractional seconds... */ else if (*(*endstr) == '.') { *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr))) *lp++ = *(*endstr)++; ftype[nf] = DTK_NUMBER; } /* * text? then date string, month, day of week, special, or timezone */ else if (isalpha((unsigned char) *(*endstr))) { ftype[nf] = DTK_STRING; *lp++ = pg_tolower((unsigned char) *(*endstr)++); while (isalpha((unsigned char) *(*endstr))) *lp++ = pg_tolower((unsigned char) *(*endstr)++); /* * Full date string with leading text month? Could also be a POSIX * time zone... */ if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.') { char *dp = (*endstr); ftype[nf] = DTK_DATE; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp) *lp++ = *(*endstr)++; } } /* skip leading spaces */ else if (isspace((unsigned char) *(*endstr))) { (*endstr)++; continue; } /* sign? then special or numeric timezone */ else if (*(*endstr) == '+' || *(*endstr) == '-') { *lp++ = *(*endstr)++; /* soak up leading whitespace */ while (isspace((unsigned char) *(*endstr))) (*endstr)++; /* numeric timezone? */ if (isdigit((unsigned char) *(*endstr))) { ftype[nf] = DTK_TZ; *lp++ = *(*endstr)++; while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == ':') || (*(*endstr) == '.')) *lp++ = *(*endstr)++; } /* special? */ else if (isalpha((unsigned char) *(*endstr))) { ftype[nf] = DTK_SPECIAL; *lp++ = pg_tolower((unsigned char) *(*endstr)++); while (isalpha((unsigned char) *(*endstr))) *lp++ = pg_tolower((unsigned char) *(*endstr)++); } /* otherwise something wrong... */ else return -1; } /* ignore punctuation but use as delimiter */ else if (ispunct((unsigned char) *(*endstr))) { (*endstr)++; continue; } /* otherwise, something is not right... */ else return -1; /* force in a delimiter after each field */ *lp++ = '\0'; nf++; if (nf > MAXDATEFIELDS) return -1; } *numfields = nf; return 0; } /* ParseDateTime() */
static int pgtypes_defmt_scan | ( | union un_fmt_comb * | scan_val, | |
int | scan_type, | |||
char ** | pstr, | |||
char * | pfmt | |||
) | [static] |
Definition at line 2537 of file dt_common.c.
References find_end_token(), un_fmt_comb::luint_val, NULL, pgtypes_strdup(), PGTYPES_TYPE_STRING_MALLOCED, PGTYPES_TYPE_UINT, PGTYPES_TYPE_UINT_LONG, un_fmt_comb::str_val, and un_fmt_comb::uint_val.
Referenced by PGTYPEStimestamp_defmt_scan().
{ /* * scan everything between pstr and pstr_end. This is not including the * last character so we might set it to '\0' for the parsing */ char last_char; int err = 0; char *pstr_end; char *strtol_end = NULL; while (**pstr == ' ') pstr++; pstr_end = find_end_token(*pstr, pfmt); if (!pstr_end) { /* there was an error, no match */ return 1; } last_char = *pstr_end; *pstr_end = '\0'; switch (scan_type) { case PGTYPES_TYPE_UINT: /* * numbers may be blank-padded, this is the only deviation from * the fmt-string we accept */ while (**pstr == ' ') (*pstr)++; errno = 0; scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10); if (errno) err = 1; break; case PGTYPES_TYPE_UINT_LONG: while (**pstr == ' ') (*pstr)++; errno = 0; scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10); if (errno) err = 1; break; case PGTYPES_TYPE_STRING_MALLOCED: scan_val->str_val = pgtypes_strdup(*pstr); if (scan_val->str_val == NULL) err = 1; break; } if (strtol_end && *strtol_end) *pstr = strtol_end; else *pstr = pstr_end; *pstr_end = last_char; return err; }
int PGTYPEStimestamp_defmt_scan | ( | char ** | str, | |
char * | fmt, | |||
timestamp * | d, | |||
int * | year, | |||
int * | month, | |||
int * | day, | |||
int * | hour, | |||
int * | minute, | |||
int * | second, | |||
int * | tz | |||
) |
Definition at line 2602 of file dt_common.c.
References day_tab, days, DecodeTimezone(), free, isleap, un_fmt_comb::luint_val, MINS_PER_HOUR, months, MONTHS_PER_YEAR, pg_strcasecmp(), pgtypes_alloc(), pgtypes_date_months, pgtypes_date_weekdays_short, pgtypes_defmt_scan(), un_fmt_comb::str_val, szdatetktbl, tm2timestamp(), un_fmt_comb::uint_val, and datetkn::value.
Referenced by PGTYPEStimestamp_defmt_asc().
{ union un_fmt_comb scan_val; int scan_type; char *pstr, *pfmt, *tmp; int err = 1; unsigned int j; struct tm tm; pfmt = fmt; pstr = *str; while (*pfmt) { err = 0; while (*pfmt == ' ') pfmt++; while (*pstr == ' ') pstr++; if (*pfmt != '%') { if (*pfmt == *pstr) { pfmt++; pstr++; } else { /* Error: no match */ err = 1; return err; } continue; } /* here *pfmt equals '%' */ pfmt++; switch (*pfmt) { case 'a': pfmt++; /* * we parse the day and see if it is a week day but we do not * check if the week day really matches the date */ err = 1; j = 0; while (pgtypes_date_weekdays_short[j]) { if (strncmp(pgtypes_date_weekdays_short[j], pstr, strlen(pgtypes_date_weekdays_short[j])) == 0) { /* found it */ err = 0; pstr += strlen(pgtypes_date_weekdays_short[j]); break; } j++; } break; case 'A': /* see note above */ pfmt++; err = 1; j = 0; while (days[j]) { if (strncmp(days[j], pstr, strlen(days[j])) == 0) { /* found it */ err = 0; pstr += strlen(days[j]); break; } j++; } break; case 'b': case 'h': pfmt++; err = 1; j = 0; while (months[j]) { if (strncmp(months[j], pstr, strlen(months[j])) == 0) { /* found it */ err = 0; pstr += strlen(months[j]); *month = j + 1; break; } j++; } break; case 'B': /* see note above */ pfmt++; err = 1; j = 0; while (pgtypes_date_months[j]) { if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0) { /* found it */ err = 0; pstr += strlen(pgtypes_date_months[j]); *month = j + 1; break; } j++; } break; case 'c': /* XXX */ break; case 'C': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *year = scan_val.uint_val * 100; break; case 'd': case 'e': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *day = scan_val.uint_val; break; case 'D': /* * we have to concatenate the strings in order to be able to * find the end of the substitution */ pfmt++; tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1); strcpy(tmp, "%m/%d/%y"); strcat(tmp, pfmt); err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); free(tmp); return err; case 'm': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *month = scan_val.uint_val; break; case 'y': case 'g': /* XXX difference to y (ISO) */ pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (*year < 0) { /* not yet set */ *year = scan_val.uint_val; } else *year += scan_val.uint_val; if (*year < 100) *year += 1900; break; case 'G': /* XXX difference to %V (ISO) */ pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *year = scan_val.uint_val; break; case 'H': case 'I': case 'k': case 'l': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *hour += scan_val.uint_val; break; case 'j': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); /* * XXX what should we do with that? We could say that it's * sufficient if we have the year and the day within the year * to get at least a specific day. */ break; case 'M': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *minute = scan_val.uint_val; break; case 'n': pfmt++; if (*pstr == '\n') pstr++; else err = 1; break; case 'p': err = 1; pfmt++; if (strncmp(pstr, "am", 2) == 0) { *hour += 0; err = 0; pstr += 2; } if (strncmp(pstr, "a.m.", 4) == 0) { *hour += 0; err = 0; pstr += 4; } if (strncmp(pstr, "pm", 2) == 0) { *hour += 12; err = 0; pstr += 2; } if (strncmp(pstr, "p.m.", 4) == 0) { *hour += 12; err = 0; pstr += 4; } break; case 'P': err = 1; pfmt++; if (strncmp(pstr, "AM", 2) == 0) { *hour += 0; err = 0; pstr += 2; } if (strncmp(pstr, "A.M.", 4) == 0) { *hour += 0; err = 0; pstr += 4; } if (strncmp(pstr, "PM", 2) == 0) { *hour += 12; err = 0; pstr += 2; } if (strncmp(pstr, "P.M.", 4) == 0) { *hour += 12; err = 0; pstr += 4; } break; case 'r': pfmt++; tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1); strcpy(tmp, "%I:%M:%S %p"); strcat(tmp, pfmt); err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); free(tmp); return err; case 'R': pfmt++; tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1); strcpy(tmp, "%H:%M"); strcat(tmp, pfmt); err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); free(tmp); return err; case 's': pfmt++; scan_type = PGTYPES_TYPE_UINT_LONG; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); /* number of seconds in scan_val.luint_val */ { struct tm *tms; time_t et = (time_t) scan_val.luint_val; tms = gmtime(&et); if (tms) { *year = tms->tm_year + 1900; *month = tms->tm_mon + 1; *day = tms->tm_mday; *hour = tms->tm_hour; *minute = tms->tm_min; *second = tms->tm_sec; } else err = 1; } break; case 'S': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *second = scan_val.uint_val; break; case 't': pfmt++; if (*pstr == '\t') pstr++; else err = 1; break; case 'T': pfmt++; tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1); strcpy(tmp, "%H:%M:%S"); strcat(tmp, pfmt); err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz); free(tmp); return err; case 'u': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (scan_val.uint_val < 1 || scan_val.uint_val > 7) err = 1; break; case 'U': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (scan_val.uint_val > 53) err = 1; break; case 'V': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (scan_val.uint_val < 1 || scan_val.uint_val > 53) err = 1; break; case 'w': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (scan_val.uint_val > 6) err = 1; break; case 'W': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (scan_val.uint_val > 53) err = 1; break; case 'x': case 'X': /* XXX */ break; case 'Y': pfmt++; scan_type = PGTYPES_TYPE_UINT; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); *year = scan_val.uint_val; break; case 'z': pfmt++; scan_type = PGTYPES_TYPE_STRING_MALLOCED; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); if (!err) { err = DecodeTimezone(scan_val.str_val, tz); free(scan_val.str_val); } break; case 'Z': pfmt++; scan_type = PGTYPES_TYPE_STRING_MALLOCED; err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt); /* * XXX use DecodeSpecial instead ? - it's declared static but * the arrays as well. :-( */ for (j = 0; !err && j < szdatetktbl; j++) { if (pg_strcasecmp(datetktbl[j].token, scan_val.str_val) == 0) { /* * tz calculates the offset for the seconds, the * timezone value of the datetktbl table is in quarter * hours */ *tz = -15 * MINS_PER_HOUR * datetktbl[j].value; break; } } free(scan_val.str_val); break; case '+': /* XXX */ break; case '%': pfmt++; if (*pstr == '%') pstr++; else err = 1; break; default: err = 1; } } if (!err) { if (*second < 0) *second = 0; if (*minute < 0) *minute = 0; if (*hour < 0) *hour = 0; if (*day < 0) { err = 1; *day = 1; } if (*month < 0) { err = 1; *month = 1; } if (*year < 0) { err = 1; *year = 1970; } if (*second > 59) { err = 1; *second = 0; } if (*minute > 59) { err = 1; *minute = 0; } if (*hour > 24 || /* test for > 24:00:00 */ (*hour == 24 && (*minute > 0 || *second > 0))) { err = 1; *hour = 0; } if (*month > MONTHS_PER_YEAR) { err = 1; *month = 1; } if (*day > day_tab[isleap(*year)][*month - 1]) { *day = day_tab[isleap(*year)][*month - 1]; err = 1; } tm.tm_sec = *second; tm.tm_min = *minute; tm.tm_hour = *hour; tm.tm_mday = *day; tm.tm_mon = *month; tm.tm_year = *year; tm2timestamp(&tm, 0, tz, d); } return err; }
void TrimTrailingZeros | ( | char * | str | ) |
Definition at line 748 of file dt_common.c.
{ int len = strlen(str); /* chop off trailing zeros... but leave at least 2 fractional digits */ while (*(str + len - 1) == '0' && *(str + len - 3) != '.') { len--; *(str + len) = '\0'; } }
Definition at line 500 of file dt_common.c.
Definition at line 26 of file dt_common.c.
int day_tab[2][13] |
{ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}
Definition at line 13 of file dt_common.c.
char* days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL} |
Definition at line 506 of file dt_common.c.
datetkn* deltacache[MAXDATEFIELDS] = {NULL} [static] |
Definition at line 502 of file dt_common.c.
datetkn deltatktbl[] [static] |
Definition at line 430 of file dt_common.c.
char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL} |
Definition at line 504 of file dt_common.c.
char* pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL} |
Definition at line 510 of file dt_common.c.
Referenced by dttofmtasc_replace(), PGTYPESdate_defmt_asc(), and PGTYPEStimestamp_defmt_scan().
char* pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL} |
Definition at line 508 of file dt_common.c.
Referenced by dttofmtasc_replace(), PGTYPESdate_fmt_asc(), and PGTYPEStimestamp_defmt_scan().
const unsigned int szdatetktbl = lengthof(datetktbl) [static] |
Definition at line 497 of file dt_common.c.
Referenced by DecodeSpecial(), and PGTYPEStimestamp_defmt_scan().
const unsigned int szdeltatktbl = lengthof(deltatktbl) [static] |
Definition at line 498 of file dt_common.c.
Referenced by DecodeUnits().