#include <pgtypes_timestamp.h>
Go to the source code of this file.
Data Structures | |
struct | datetkn |
Defines | |
#define | MAXTZLEN 10 |
#define | TS_PREC_INV 1000000.0 |
#define | TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) |
#define | USE_POSTGRES_DATES 0 |
#define | USE_ISO_DATES 1 |
#define | USE_SQL_DATES 2 |
#define | USE_GERMAN_DATES 3 |
#define | INTSTYLE_POSTGRES 0 |
#define | INTSTYLE_POSTGRES_VERBOSE 1 |
#define | INTSTYLE_SQL_STANDARD 2 |
#define | INTSTYLE_ISO_8601 3 |
#define | INTERVAL_FULL_RANGE (0x7FFF) |
#define | INTERVAL_MASK(b) (1 << (b)) |
#define | MAX_INTERVAL_PRECISION 6 |
#define | DTERR_BAD_FORMAT (-1) |
#define | DTERR_FIELD_OVERFLOW (-2) |
#define | DTERR_MD_FIELD_OVERFLOW (-3) |
#define | DTERR_INTERVAL_OVERFLOW (-4) |
#define | DTERR_TZDISP_OVERFLOW (-5) |
#define | DAGO "ago" |
#define | EPOCH "epoch" |
#define | INVALID "invalid" |
#define | EARLY "-infinity" |
#define | LATE "infinity" |
#define | NOW "now" |
#define | TODAY "today" |
#define | TOMORROW "tomorrow" |
#define | YESTERDAY "yesterday" |
#define | ZULU "zulu" |
#define | DMICROSEC "usecond" |
#define | DMILLISEC "msecond" |
#define | DSECOND "second" |
#define | DMINUTE "minute" |
#define | DHOUR "hour" |
#define | DDAY "day" |
#define | DWEEK "week" |
#define | DMONTH "month" |
#define | DQUARTER "quarter" |
#define | DYEAR "year" |
#define | DDECADE "decade" |
#define | DCENTURY "century" |
#define | DMILLENNIUM "millennium" |
#define | DA_D "ad" |
#define | DB_C "bc" |
#define | DTIMEZONE "timezone" |
#define | DCURRENT "current" |
#define | AM 0 |
#define | PM 1 |
#define | HR24 2 |
#define | AD 0 |
#define | BC 1 |
#define | RESERV 0 |
#define | MONTH 1 |
#define | YEAR 2 |
#define | DAY 3 |
#define | JULIAN 4 |
#define | TZ 5 |
#define | DTZ 6 |
#define | DTZMOD 7 |
#define | IGNORE_DTF 8 |
#define | AMPM 9 |
#define | HOUR 10 |
#define | MINUTE 11 |
#define | SECOND 12 |
#define | MILLISECOND 13 |
#define | MICROSECOND 14 |
#define | DOY 15 |
#define | DOW 16 |
#define | UNITS 17 |
#define | ADBC 18 |
#define | AGO 19 |
#define | ABS_BEFORE 20 |
#define | ABS_AFTER 21 |
#define | ISODATE 22 |
#define | ISOTIME 23 |
#define | UNKNOWN_FIELD 31 |
#define | DTK_NUMBER 0 |
#define | DTK_STRING 1 |
#define | DTK_DATE 2 |
#define | DTK_TIME 3 |
#define | DTK_TZ 4 |
#define | DTK_AGO 5 |
#define | DTK_SPECIAL 6 |
#define | DTK_INVALID 7 |
#define | DTK_CURRENT 8 |
#define | DTK_EARLY 9 |
#define | DTK_LATE 10 |
#define | DTK_EPOCH 11 |
#define | DTK_NOW 12 |
#define | DTK_YESTERDAY 13 |
#define | DTK_TODAY 14 |
#define | DTK_TOMORROW 15 |
#define | DTK_ZULU 16 |
#define | DTK_DELTA 17 |
#define | DTK_SECOND 18 |
#define | DTK_MINUTE 19 |
#define | DTK_HOUR 20 |
#define | DTK_DAY 21 |
#define | DTK_WEEK 22 |
#define | DTK_MONTH 23 |
#define | DTK_QUARTER 24 |
#define | DTK_YEAR 25 |
#define | DTK_DECADE 26 |
#define | DTK_CENTURY 27 |
#define | DTK_MILLENNIUM 28 |
#define | DTK_MILLISEC 29 |
#define | DTK_MICROSEC 30 |
#define | DTK_JULIAN 31 |
#define | DTK_DOW 32 |
#define | DTK_DOY 33 |
#define | DTK_TZ_HOUR 34 |
#define | DTK_TZ_MINUTE 35 |
#define | DTK_ISOYEAR 36 |
#define | DTK_ISODOW 37 |
#define | DTK_M(t) (0x01 << (t)) |
#define | DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND)) |
#define | DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) |
#define | DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) |
#define | MAXDATELEN 63 |
#define | MAXDATEFIELDS 25 |
#define | TOKMAXLEN 10 |
#define | FMODULO(t, q, u) |
#define | TMODULO(t, q, u) |
#define | DAYS_PER_YEAR 365.25 |
#define | MONTHS_PER_YEAR 12 |
#define | DAYS_PER_MONTH 30 |
#define | HOURS_PER_DAY 24 |
#define | SECS_PER_YEAR (36525 * 864) |
#define | SECS_PER_DAY 86400 |
#define | SECS_PER_HOUR 3600 |
#define | SECS_PER_MINUTE 60 |
#define | MINS_PER_HOUR 60 |
#define | isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) |
#define | JULIAN_MINYEAR (-4713) |
#define | JULIAN_MINMONTH (11) |
#define | JULIAN_MINDAY (24) |
#define | JULIAN_MAXYEAR (5874898) |
#define | IS_VALID_JULIAN(y, m, d) |
#define | UTIME_MINYEAR (1901) |
#define | UTIME_MINMONTH (12) |
#define | UTIME_MINDAY (14) |
#define | UTIME_MAXYEAR (2038) |
#define | UTIME_MAXMONTH (01) |
#define | UTIME_MAXDAY (18) |
#define | IS_VALID_UTIME(y, m, d) |
#define | DT_NOBEGIN (-DBL_MAX) |
#define | DT_NOEND (DBL_MAX) |
#define | TIMESTAMP_NOBEGIN(j) do {(j) = DT_NOBEGIN;} while (0) |
#define | TIMESTAMP_NOEND(j) do {(j) = DT_NOEND;} while (0) |
#define | TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) |
#define | TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND) |
#define | TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) |
Typedefs | |
typedef double | fsec_t |
Functions | |
int | DecodeInterval (char **, int *, int, int *, struct tm *, fsec_t *) |
int | DecodeTime (char *, int *, struct tm *, fsec_t *) |
int | EncodeDateTime (struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates) |
int | EncodeInterval (struct tm *tm, fsec_t fsec, int style, char *str) |
int | tm2timestamp (struct tm *, fsec_t, int *, timestamp *) |
int | DecodeUnits (int field, char *lowtoken, int *val) |
bool | CheckDateTokenTables (void) |
int | EncodeDateOnly (struct tm *tm, int style, char *str, bool EuroDates) |
int | GetEpochTime (struct tm *) |
int | ParseDateTime (char *, char *, char **, int *, int *, char **) |
int | DecodeDateTime (char **, int *, int, int *, struct tm *, fsec_t *, bool) |
void | j2date (int, int *, int *, int *) |
void | GetCurrentDateTime (struct tm *) |
int | date2j (int, int, int) |
void | TrimTrailingZeros (char *) |
void | dt2time (double, int *, int *, int *, fsec_t *) |
Variables | |
char * | pgtypes_date_weekdays_short [] |
char * | pgtypes_date_months [] |
char * | months [] |
char * | days [] |
int | day_tab [2][13] |
#define DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND)) |
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) |
#define FMODULO | ( | t, | ||
q, | ||||
u | ||||
) |
#define IS_VALID_JULIAN | ( | y, | ||
m, | ||||
d | ||||
) |
((((y) > JULIAN_MINYEAR) \ || (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \ || (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY))))) \ && ((y) < JULIAN_MAXYEAR))
#define IS_VALID_UTIME | ( | y, | ||
m, | ||||
d | ||||
) |
((((y) > UTIME_MINYEAR) \ || (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \ || (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \ && (((y) < UTIME_MAXYEAR) \ || (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \ || (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY))))))
Definition at line 307 of file dt.h.
Referenced by timestamp2tm().
#define isleap | ( | y | ) | (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) |
#define TIMESTAMP_NOBEGIN | ( | j | ) | do {(j) = DT_NOBEGIN;} while (0) |
#define TIMESTAMP_NOT_FINITE | ( | j | ) | (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) |
#define TMODULO | ( | t, | ||
q, | ||||
u | ||||
) |
#define TSROUND | ( | j | ) | (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) |
bool CheckDateTokenTables | ( | void | ) |
Definition at line 4158 of file datetime.c.
References Assert, CheckDateTokenTable(), date2j(), POSTGRES_EPOCH_JDATE, szdatetktbl, szdeltatktbl, and UNIX_EPOCH_JDATE.
Referenced by PostmasterMain().
{ bool ok = true; Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1)); Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1)); ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl); ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl); return ok; }
int date2j | ( | int | , | |
int | , | |||
int | ||||
) |
Definition at line 301 of file datetime.c.
Referenced by abstime_date(), CheckDateTokenTables(), date2isoweek(), date2isoyear(), date2isoyearday(), date_in(), DCH_to_char(), DecodeDateTime(), DecodeNumber(), DetermineTimeZoneOffset(), EncodeDateTime(), isoweek2j(), PGTYPESdate_dayofweek(), PGTYPESdate_defmt_asc(), PGTYPESdate_fmt_asc(), PGTYPESdate_from_asc(), PGTYPESdate_julmdy(), PGTYPESdate_mdyjul(), PGTYPESdate_to_asc(), PGTYPESdate_today(), timestamp2tm(), timestamp_date(), timestamp_part(), timestamp_pl_interval(), timestamp_to_char(), timestamptz_date(), timestamptz_part(), timestamptz_pl_interval(), timestamptz_to_char(), tm2abstime(), tm2timestamp(), to_date(), and ValidateDate().
{ 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 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() */
Definition at line 342 of file interval.c.
References AdjustFractDays(), AdjustFractSeconds(), AGO, ClearPgTm(), DAY, DAYS_PER_MONTH, DecodeTime(), DecodeUnits(), DTK_CENTURY, DTK_DATE, DTK_DATE_M, DTK_DAY, DTK_DECADE, DTK_HOUR, DTK_M, DTK_MICROSEC, DTK_MILLENNIUM, DTK_MILLISEC, DTK_MINUTE, DTK_MONTH, DTK_NUMBER, DTK_SECOND, DTK_SPECIAL, DTK_STRING, DTK_TIME, DTK_TZ, DTK_WEEK, DTK_YEAR, HOUR, i, IGNORE_DTF, INTERVAL_MASK, IntervalStyle, INTSTYLE_SQL_STANDARD, MICROSECOND, MILLISECOND, MINUTE, MONTH, MONTHS_PER_YEAR, NULL, range(), RESERV, rint(), SECOND, SECS_PER_DAY, SECS_PER_HOUR, SECS_PER_MINUTE, strtoi(), TMODULO, TZ, UNITS, val, and YEAR.
{ int IntervalStyle = INTSTYLE_POSTGRES_VERBOSE; int range = INTERVAL_FULL_RANGE; bool is_before = FALSE; char *cp; int fmask = 0, tmask, type; int i; int dterr; int val; double fval; *dtype = DTK_DELTA; type = IGNORE_DTF; ClearPgTm(tm, fsec); /* read through list backwards to pick up units before values */ for (i = nf - 1; i >= 0; i--) { switch (ftype[i]) { case DTK_TIME: dterr = DecodeTime(field[i], /* range, */ &tmask, tm, fsec); if (dterr) return dterr; type = DTK_DAY; break; case DTK_TZ: /* * Timezone is a token with a leading sign character and at * least one digit; there could be ':', '.', '-' embedded in * it as well. */ /* Assert(*field[i] == '-' || *field[i] == '+'); */ /* * Try for hh:mm or hh:mm:ss. If not, fall through to * DTK_NUMBER case, which can handle signed float numbers and * signed year-month values. */ if (strchr(field[i] + 1, ':') != NULL && DecodeTime(field[i] + 1, /* INTERVAL_FULL_RANGE, */ &tmask, tm, fsec) == 0) { if (*field[i] == '-') { /* flip the sign on all fields */ tm->tm_hour = -tm->tm_hour; tm->tm_min = -tm->tm_min; tm->tm_sec = -tm->tm_sec; *fsec = -(*fsec); } /* * Set the next type to be a day, if units are not * specified. This handles the case of '1 +02:03' since we * are reading right to left. */ type = DTK_DAY; tmask = DTK_M(TZ); break; } /* FALL THROUGH */ case DTK_DATE: case DTK_NUMBER: if (type == IGNORE_DTF) { /* use typmod to decide what rightmost field is */ switch (range) { case INTERVAL_MASK(YEAR): type = DTK_YEAR; break; case INTERVAL_MASK(MONTH): case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): type = DTK_MONTH; break; case INTERVAL_MASK(DAY): type = DTK_DAY; break; case INTERVAL_MASK(HOUR): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): type = DTK_HOUR; break; case INTERVAL_MASK(MINUTE): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): type = DTK_MINUTE; break; case INTERVAL_MASK(SECOND): case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): type = DTK_SECOND; break; default: type = DTK_SECOND; break; } } errno = 0; val = strtoi(field[i], &cp, 10); if (errno == ERANGE) return DTERR_FIELD_OVERFLOW; if (*cp == '-') { /* SQL "years-months" syntax */ int val2; val2 = strtoi(cp + 1, &cp, 10); if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR) return DTERR_FIELD_OVERFLOW; if (*cp != '\0') return DTERR_BAD_FORMAT; type = DTK_MONTH; if (*field[i] == '-') val2 = -val2; val = val * MONTHS_PER_YEAR + val2; fval = 0; } else if (*cp == '.') { errno = 0; fval = strtod(cp, &cp); if (*cp != '\0' || errno != 0) return DTERR_BAD_FORMAT; if (*field[i] == '-') fval = -fval; } else if (*cp == '\0') fval = 0; else return DTERR_BAD_FORMAT; tmask = 0; /* DTK_M(type); */ switch (type) { case DTK_MICROSEC: #ifdef HAVE_INT64_TIMESTAMP *fsec += rint(val + fval); #else *fsec += (val + fval) * 1e-6; #endif tmask = DTK_M(MICROSECOND); break; case DTK_MILLISEC: #ifdef HAVE_INT64_TIMESTAMP *fsec += rint((val + fval) * 1000); #else *fsec += (val + fval) * 1e-3; #endif tmask = DTK_M(MILLISECOND); break; case DTK_SECOND: tm->tm_sec += val; #ifdef HAVE_INT64_TIMESTAMP *fsec += rint(fval * 1000000); #else *fsec += fval; #endif /* * If any subseconds were specified, consider this * microsecond and millisecond input as well. */ if (fval == 0) tmask = DTK_M(SECOND); else tmask = DTK_ALL_SECS_M; break; case DTK_MINUTE: tm->tm_min += val; AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE); tmask = DTK_M(MINUTE); break; case DTK_HOUR: tm->tm_hour += val; AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR); tmask = DTK_M(HOUR); type = DTK_DAY; break; case DTK_DAY: tm->tm_mday += val; AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY); tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY); break; case DTK_WEEK: tm->tm_mday += val * 7; AdjustFractDays(fval, tm, fsec, 7); tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY); break; case DTK_MONTH: tm->tm_mon += val; AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH); tmask = DTK_M(MONTH); break; case DTK_YEAR: tm->tm_year += val; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_DECADE: tm->tm_year += val * 10; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 10; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_CENTURY: tm->tm_year += val * 100; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 100; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; case DTK_MILLENNIUM: tm->tm_year += val * 1000; if (fval != 0) tm->tm_mon += fval * MONTHS_PER_YEAR * 1000; tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR); break; default: return DTERR_BAD_FORMAT; } break; case DTK_STRING: case DTK_SPECIAL: type = DecodeUnits(i, field[i], &val); if (type == IGNORE_DTF) continue; tmask = 0; /* DTK_M(type); */ switch (type) { case UNITS: type = val; break; case AGO: is_before = TRUE; type = val; break; case RESERV: tmask = (DTK_DATE_M | DTK_TIME_M); *dtype = val; break; default: return DTERR_BAD_FORMAT; } break; default: return DTERR_BAD_FORMAT; } if (tmask & fmask) return DTERR_BAD_FORMAT; fmask |= tmask; } /* ensure that at least one time field has been found */ if (fmask == 0) return DTERR_BAD_FORMAT; /* ensure fractional seconds are fractional */ if (*fsec != 0) { int sec; #ifdef HAVE_INT64_TIMESTAMP sec = *fsec / USECS_PER_SEC; *fsec -= sec * USECS_PER_SEC; #else TMODULO(*fsec, sec, 1.0); #endif tm->tm_sec += sec; } /*---------- * The SQL standard defines the interval literal * '-1 1:00:00' * to mean "negative 1 days and negative 1 hours", while Postgres * traditionally treats this as meaning "negative 1 days and positive * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign * to all fields if there are no other explicit signs. * * We leave the signs alone if there are additional explicit signs. * This protects us against misinterpreting postgres-style dump output, * since the postgres-style output code has always put an explicit sign on * all fields following a negative field. But note that SQL-spec output * is ambiguous and can be misinterpreted on load! (So it's best practice * to dump in postgres style, not SQL style.) *---------- */ if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-') { /* Check for additional explicit signs */ bool more_signs = false; for (i = 1; i < nf; i++) { if (*field[i] == '-' || *field[i] == '+') { more_signs = true; break; } } if (!more_signs) { /* * Rather than re-determining which field was field[0], just force * 'em all negative. */ if (*fsec > 0) *fsec = -(*fsec); if (tm->tm_sec > 0) tm->tm_sec = -tm->tm_sec; if (tm->tm_min > 0) tm->tm_min = -tm->tm_min; if (tm->tm_hour > 0) tm->tm_hour = -tm->tm_hour; if (tm->tm_mday > 0) tm->tm_mday = -tm->tm_mday; if (tm->tm_mon > 0) tm->tm_mon = -tm->tm_mon; if (tm->tm_year > 0) tm->tm_year = -tm->tm_year; } } /* finally, AGO negates everything */ if (is_before) { *fsec = -(*fsec); tm->tm_sec = -tm->tm_sec; tm->tm_min = -tm->tm_min; tm->tm_hour = -tm->tm_hour; tm->tm_mday = -tm->tm_mday; tm->tm_mon = -tm->tm_mon; tm->tm_year = -tm->tm_year; } return 0; }
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() */
int DecodeUnits | ( | int | field, | |
char * | lowtoken, | |||
int * | val | |||
) |
Definition at line 3498 of file datetime.c.
References datebsearch(), DTZ, FROMVAL, NULL, szdeltatktbl, datetkn::token, TOKMAXLEN, datetkn::type, TZ, and datetkn::value.
Referenced by DecodeInterval(), interval_part(), interval_trunc(), time_part(), timestamp_part(), timestamp_trunc(), timestamptz_part(), timestamptz_trunc(), and timetz_part().
{ int type; const datetkn *tp; tp = deltacache[field]; if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0) { tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); } if (tp == NULL) { type = UNKNOWN_FIELD; *val = 0; } else { deltacache[field] = tp; type = tp->type; if (type == TZ || type == DTZ) *val = FROMVAL(tp); else *val = tp->value; } return type; } /* DecodeUnits() */
void dt2time | ( | double | , | |
int * | , | |||
int * | , | |||
int * | , | |||
fsec_t * | ||||
) |
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() */
Definition at line 802 of file interval.c.
References AddISO8601IntPart(), AddPostgresIntPart(), AddVerboseIntPart(), AppendSeconds(), INTSTYLE_ISO_8601, INTSTYLE_POSTGRES, INTSTYLE_POSTGRES_VERBOSE, INTSTYLE_SQL_STANDARD, and MAX_INTERVAL_PRECISION.
{ char *cp = str; int year = tm->tm_year; int mon = tm->tm_mon; int mday = tm->tm_mday; int hour = tm->tm_hour; int min = tm->tm_min; int sec = tm->tm_sec; bool is_before = FALSE; bool is_zero = TRUE; /* * The sign of year and month are guaranteed to match, since they are * stored internally as "month". But we'll need to check for is_before and * is_zero when determining the signs of day and hour/minute/seconds * fields. */ switch (style) { /* SQL Standard interval format */ case INTSTYLE_SQL_STANDARD: { bool has_negative = year < 0 || mon < 0 || mday < 0 || hour < 0 || min < 0 || sec < 0 || fsec < 0; bool has_positive = year > 0 || mon > 0 || mday > 0 || hour > 0 || min > 0 || sec > 0 || fsec > 0; bool has_year_month = year != 0 || mon != 0; bool has_day_time = mday != 0 || hour != 0 || min != 0 || sec != 0 || fsec != 0; bool has_day = mday != 0; bool sql_standard_value = !(has_negative && has_positive) && !(has_year_month && has_day_time); /* * SQL Standard wants only 1 "<sign>" preceding the whole * interval ... but can't do that if mixed signs. */ if (has_negative && sql_standard_value) { *cp++ = '-'; year = -year; mon = -mon; mday = -mday; hour = -hour; min = -min; sec = -sec; fsec = -fsec; } if (!has_negative && !has_positive) { sprintf(cp, "0"); } else if (!sql_standard_value) { /* * For non sql-standard interval values, force outputting * the signs to avoid ambiguities with intervals with * mixed sign components. */ char year_sign = (year < 0 || mon < 0) ? '-' : '+'; char day_sign = (mday < 0) ? '-' : '+'; char sec_sign = (hour < 0 || min < 0 || sec < 0 || fsec < 0) ? '-' : '+'; sprintf(cp, "%c%d-%d %c%d %c%d:%02d:", year_sign, abs(year), abs(mon), day_sign, abs(mday), sec_sign, abs(hour), abs(min)); cp += strlen(cp); AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true); } else if (has_year_month) { sprintf(cp, "%d-%d", year, mon); } else if (has_day) { sprintf(cp, "%d %d:%02d:", mday, hour, min); cp += strlen(cp); AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true); } else { sprintf(cp, "%d:%02d:", hour, min); cp += strlen(cp); AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true); } } break; /* ISO 8601 "time-intervals by duration only" */ case INTSTYLE_ISO_8601: /* special-case zero to avoid printing nothing */ if (year == 0 && mon == 0 && mday == 0 && hour == 0 && min == 0 && sec == 0 && fsec == 0) { sprintf(cp, "PT0S"); break; } *cp++ = 'P'; cp = AddISO8601IntPart(cp, year, 'Y'); cp = AddISO8601IntPart(cp, mon, 'M'); cp = AddISO8601IntPart(cp, mday, 'D'); if (hour != 0 || min != 0 || sec != 0 || fsec != 0) *cp++ = 'T'; cp = AddISO8601IntPart(cp, hour, 'H'); cp = AddISO8601IntPart(cp, min, 'M'); if (sec != 0 || fsec != 0) { if (sec < 0 || fsec < 0) *cp++ = '-'; AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false); cp += strlen(cp); *cp++ = 'S'; *cp = '\0'; } break; /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */ case INTSTYLE_POSTGRES: cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before); cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before); cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before); if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0) { bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0); sprintf(cp, "%s%s%02d:%02d:", is_zero ? "" : " ", (minus ? "-" : (is_before ? "+" : "")), abs(hour), abs(min)); cp += strlen(cp); AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true); } break; /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */ case INTSTYLE_POSTGRES_VERBOSE: default: strcpy(cp, "@"); cp++; cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before); cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before); cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before); cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before); cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before); if (sec != 0 || fsec != 0) { *cp++ = ' '; if (sec < 0 || (sec == 0 && fsec < 0)) { if (is_zero) is_before = TRUE; else if (!is_before) *cp++ = '-'; } else if (is_before) *cp++ = '-'; AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false); cp += strlen(cp); sprintf(cp, " sec%s", (abs(sec) != 1 || fsec != 0) ? "s" : ""); is_zero = FALSE; } /* identically zero? then put in a unitless zero... */ if (is_zero) strcat(cp, " 0"); if (is_before) strcat(cp, " ago"); break; } return 0; } /* EncodeInterval() */
void GetCurrentDateTime | ( | struct 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 * | ) |
Definition at line 1012 of file dt_common.c.
References epoch.
void j2date | ( | int | , | |
int * | , | |||
int * | , | |||
int * | ||||
) |
Definition at line 326 of file datetime.c.
References MONTHS_PER_YEAR.
Referenced by date2timestamptz(), date_out(), DecodeDateTime(), DecodeNumber(), DecodeTimeOnly(), do_to_timestamp(), isoweek2date(), isoweekdate2date(), map_sql_value_to_xml_value(), PGTYPESdate_fmt_asc(), PGTYPESdate_julmdy(), PGTYPESdate_to_asc(), timestamp2tm(), timestamp_pl_interval(), timestamptz_pl_interval(), and ValidateDate().
{ 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) % MONTHS_PER_YEAR + 1; return; } /* j2date() */
int ParseDateTime | ( | char * | , | |
char * | , | |||
char ** | , | |||
int * | , | |||
int * | , | |||
char ** | ||||
) |
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() */
Definition at line 57 of file timestamp.c.
References date2j(), dt2local(), IS_VALID_JULIAN, NULL, SECS_PER_DAY, time2t(), and USECS_PER_DAY.
{ #ifdef HAVE_INT64_TIMESTAMP int dDate; int64 time; #else double dDate, time; #endif /* Julian day routines are not correct for negative Julian days */ if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) return -1; dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec); #ifdef HAVE_INT64_TIMESTAMP *result = (dDate * USECS_PER_DAY) + time; /* check for major overflow */ if ((*result - time) / USECS_PER_DAY != dDate) return -1; /* check for just-barely overflow (okay except time-of-day wraps) */ /* caution: we want to allow 1999-12-31 24:00:00 */ if ((*result < 0 && dDate > 0) || (*result > 0 && dDate < -1)) return -1; #else *result = dDate * SECS_PER_DAY + time; #endif if (tzp != NULL) *result = dt2local(*result, -(*tzp)); return 0; } /* tm2timestamp() */
void TrimTrailingZeros | ( | char * | ) |
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'; } }
int day_tab[2][13] |
Definition at line 58 of file datetime.c.
Referenced by DecodeDateTime(), PGTYPEStimestamp_add_interval(), PGTYPEStimestamp_defmt_scan(), timestamp_age(), timestamp_pl_interval(), timestamptz_age(), timestamptz_pl_interval(), and ValidateDate().
char* days[] |
Definition at line 67 of file datetime.c.
Referenced by date_mii(), date_pli(), DCH_from_char(), DCH_to_char(), dttofmtasc_replace(), EncodeDateTime(), interval_time(), and PGTYPEStimestamp_defmt_scan().
char* months[] |
Definition at line 64 of file datetime.c.
Referenced by DCH_from_char(), DCH_to_char(), dttofmtasc_replace(), EncodeDateTime(), PGTYPESdate_defmt_asc(), PGTYPESdate_fmt_asc(), and PGTYPEStimestamp_defmt_scan().
char* pgtypes_date_months[] |
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[] |
Definition at line 508 of file dt_common.c.
Referenced by dttofmtasc_replace(), PGTYPESdate_fmt_asc(), and PGTYPEStimestamp_defmt_scan().