1 /*-------------------------------------------------------------------------
4 * Support functions for date/time types.
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/datetime.c
13 *-------------------------------------------------------------------------
22 #include "access/htup_details.h"
23 #include "access/xact.h"
24 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "nodes/nodeFuncs.h"
28 #include "utils/builtins.h"
29 #include "utils/date.h"
30 #include "utils/datetime.h"
31 #include "utils/memutils.h"
32 #include "utils/tzparser.h"
35 static int DecodeNumber(int flen, char *field, bool haveTextMonth,
36 int fmask, int *tmask,
37 struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
38 static int DecodeNumberField(int len, char *str,
39 int fmask, int *tmask,
40 struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
41 static int DecodeTime(char *str, int fmask, int range,
42 int *tmask, struct pg_tm * tm, fsec_t *fsec);
43 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
44 static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
47 #ifndef HAVE_INT64_TIMESTAMP
48 static char *TrimTrailingZeros(char *str);
49 #endif /* HAVE_INT64_TIMESTAMP */
51 static char *AppendSeconds(char *cp, int sec, fsec_t fsec,
52 int precision, bool fillzeros);
53 static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec,
55 static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
57 static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp,
59 static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t,
60 const char *abbr, pg_tz *tzp,
61 int *offset, int *isdst);
62 static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
65 const int day_tab[2][13] =
67 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
68 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}
71 const char *const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
72 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
74 const char *const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
75 "Thursday", "Friday", "Saturday", NULL};
78 /*****************************************************************************
80 *****************************************************************************/
83 * datetktbl holds date/time keywords.
85 * Note that this table must be strictly alphabetically ordered to allow an
86 * O(ln(N)) search algorithm to be used.
88 * The token field must be NUL-terminated; we truncate entries to TOKMAXLEN
91 * The static table contains no TZ, DTZ, or DYNTZ entries; rather those
92 * are loaded from configuration files and stored in zoneabbrevtbl, whose
93 * abbrevs[] field has the same format as the static datetktbl.
95 static const datetkn datetktbl[] = {
96 /* token, type, value */
97 {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
98 {DA_D, ADBC, AD}, /* "ad" for years > 0 */
99 {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
103 {"at", IGNORE_DTF, 0}, /* "at" (throwaway) */
105 {"august", MONTH, 8},
106 {DB_C, ADBC, BC}, /* "bc" for years <= 0 */
107 {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
108 {"d", UNITS, DTK_DAY}, /* "day of month" for ISO input */
110 {"december", MONTH, 12},
111 {"dow", UNITS, DTK_DOW}, /* day of week */
112 {"doy", UNITS, DTK_DOY}, /* day of year */
113 {"dst", DTZMOD, SECS_PER_HOUR},
114 {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
116 {"february", MONTH, 2},
119 {"h", UNITS, DTK_HOUR}, /* "hour" */
120 {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
121 {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */
122 {"isodow", UNITS, DTK_ISODOW}, /* ISO day of week, Sunday == 7 */
123 {"isoyear", UNITS, DTK_ISOYEAR}, /* year in terms of the ISO week date */
124 {"j", UNITS, DTK_JULIAN},
126 {"january", MONTH, 1},
127 {"jd", UNITS, DTK_JULIAN},
129 {"julian", UNITS, DTK_JULIAN},
133 {"m", UNITS, DTK_MONTH}, /* "month" for ISO input */
137 {"mm", UNITS, DTK_MINUTE}, /* "minute" for ISO input */
141 {"november", MONTH, 11},
142 {NOW, RESERV, DTK_NOW}, /* current transaction time */
144 {"october", MONTH, 10},
145 {"on", IGNORE_DTF, 0}, /* "on" (throwaway) */
147 {"s", UNITS, DTK_SECOND}, /* "seconds" for ISO input */
149 {"saturday", DOW, 6},
152 {"september", MONTH, 9},
155 {"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
159 {"thursday", DOW, 4},
160 {TODAY, RESERV, DTK_TODAY}, /* midnight */
161 {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
165 {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
167 {"wednesday", DOW, 3},
169 {"y", UNITS, DTK_YEAR}, /* "year" for ISO input */
170 {YESTERDAY, RESERV, DTK_YESTERDAY} /* yesterday midnight */
173 static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
176 * deltatktbl: same format as datetktbl, but holds keywords used to represent
177 * time units (eg, for intervals, and for EXTRACT).
179 static const datetkn deltatktbl[] = {
180 /* token, type, value */
181 {"@", IGNORE_DTF, 0}, /* postgres relative prefix */
182 {DAGO, AGO, 0}, /* "ago" indicates negative time offset */
183 {"c", UNITS, DTK_CENTURY}, /* "century" relative */
184 {"cent", UNITS, DTK_CENTURY}, /* "century" relative */
185 {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative */
186 {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */
187 {"d", UNITS, DTK_DAY}, /* "day" relative */
188 {DDAY, UNITS, DTK_DAY}, /* "day" relative */
189 {"days", UNITS, DTK_DAY}, /* "days" relative */
190 {"dec", UNITS, DTK_DECADE}, /* "decade" relative */
191 {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative */
192 {"decades", UNITS, DTK_DECADE}, /* "decades" relative */
193 {"decs", UNITS, DTK_DECADE}, /* "decades" relative */
194 {"h", UNITS, DTK_HOUR}, /* "hour" relative */
195 {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative */
196 {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
197 {"hr", UNITS, DTK_HOUR}, /* "hour" relative */
198 {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */
199 {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */
200 {"m", UNITS, DTK_MINUTE}, /* "minute" relative */
201 {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
202 {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
203 {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
204 {DMILLENNIUM, UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
205 {"millisecon", UNITS, DTK_MILLISEC}, /* relative */
206 {"mils", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
207 {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
208 {"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */
209 {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative */
210 {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
211 {"mon", UNITS, DTK_MONTH}, /* "months" relative */
212 {"mons", UNITS, DTK_MONTH}, /* "months" relative */
213 {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
214 {"months", UNITS, DTK_MONTH},
215 {"ms", UNITS, DTK_MILLISEC},
216 {"msec", UNITS, DTK_MILLISEC},
217 {DMILLISEC, UNITS, DTK_MILLISEC},
218 {"mseconds", UNITS, DTK_MILLISEC},
219 {"msecs", UNITS, DTK_MILLISEC},
220 {"qtr", UNITS, DTK_QUARTER}, /* "quarter" relative */
221 {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
222 {"s", UNITS, DTK_SECOND},
223 {"sec", UNITS, DTK_SECOND},
224 {DSECOND, UNITS, DTK_SECOND},
225 {"seconds", UNITS, DTK_SECOND},
226 {"secs", UNITS, DTK_SECOND},
227 {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
228 {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
229 {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
230 {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
231 {"us", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
232 {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
233 {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative */
234 {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
235 {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
236 {"w", UNITS, DTK_WEEK}, /* "week" relative */
237 {DWEEK, UNITS, DTK_WEEK}, /* "week" relative */
238 {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
239 {"y", UNITS, DTK_YEAR}, /* "year" relative */
240 {DYEAR, UNITS, DTK_YEAR}, /* "year" relative */
241 {"years", UNITS, DTK_YEAR}, /* "years" relative */
242 {"yr", UNITS, DTK_YEAR}, /* "year" relative */
243 {"yrs", UNITS, DTK_YEAR} /* "years" relative */
246 static int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
248 static TimeZoneAbbrevTable *zoneabbrevtbl = NULL;
250 /* Caches of recent lookup results in the above tables */
252 static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
254 static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
256 static const datetkn *abbrevcache[MAXDATEFIELDS] = {NULL};
260 * strtoint --- just like strtol, but returns int not long
263 strtoint(const char *nptr, char **endptr, int base)
267 val = strtol(nptr, endptr, base);
268 #ifdef HAVE_LONG_INT_64
269 if (val != (long) ((int32) val))
277 * Calendar time to Julian date conversions.
278 * Julian date is commonly used in astronomical applications,
279 * since it is numerically accurate and computationally simple.
280 * The algorithms here will accurately convert between Julian day
281 * and calendar date for all non-negative Julian days
282 * (i.e. from Nov 24, -4713 on).
284 * Rewritten to eliminate overflow problems. This now allows the
285 * routines to work correctly for all Julian day counts from
286 * 0 to 2147483647 (Nov 24, -4713 to Jun 3, 5874898) assuming
287 * a 32-bit integer. Longer types should also work to the limits
288 * of their precision.
290 * Actually, date2j() will work sanely, in the sense of producing
291 * valid negative Julian dates, significantly before Nov 24, -4713.
292 * We rely on it to do so back to Nov 1, -4713; see IS_VALID_JULIAN()
293 * and associated commentary in timestamp.h.
297 date2j(int y, int m, int d)
314 julian = y * 365 - 32167;
315 julian += y / 4 - century + century / 4;
316 julian += 7834 * m / 256 + d;
322 j2date(int jd, int *year, int *month, int *day)
331 quad = julian / 146097;
332 extra = (julian - quad * 146097) * 4 + 3;
333 julian += 60 + quad * 3 + extra / 146097;
334 quad = julian / 1461;
335 julian -= quad * 1461;
336 y = julian * 4 / 1461;
337 julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
341 quad = julian * 2141 / 65536;
342 *day = julian - 7834 * quad / 256;
343 *month = (quad + 10) % MONTHS_PER_YEAR + 1;
350 * j2day - convert Julian date to day-of-week (0..6 == Sun..Sat)
352 * Note: various places use the locution j2day(date - 1) to produce a
353 * result according to the convention 0..6 = Mon..Sun. This is a bit of
354 * a crock, but will work as long as the computation here is just a modulo.
361 /* Cope if division truncates towards zero, as it probably does */
370 * GetCurrentDateTime()
372 * Get the transaction start time ("now()") broken down as a struct pg_tm.
375 GetCurrentDateTime(struct pg_tm * tm)
380 timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, &fsec,
382 /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
386 * GetCurrentTimeUsec()
388 * Get the transaction start time ("now()") broken down as a struct pg_tm,
389 * including fractional seconds and timezone offset.
392 GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp)
396 timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, fsec,
398 /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
404 /* TrimTrailingZeros()
405 * ... resulting from printing numbers with full precision.
407 * Returns a pointer to the new end of string. No NUL terminator is put
408 * there; callers are responsible for NUL terminating str themselves.
410 * Before Postgres 8.4, this always left at least 2 fractional digits,
411 * but conversations on the lists suggest this isn't desired
412 * since showing '0.10' is misleading with values of precision(1).
414 #ifndef HAVE_INT64_TIMESTAMP
416 TrimTrailingZeros(char *str)
418 int len = strlen(str);
420 while (len > 1 && *(str + len - 1) == '0' && *(str + len - 2) != '.')
424 #endif /* HAVE_INT64_TIMESTAMP */
427 * Append seconds and fractional seconds (if any) at *cp.
429 * precision is the max number of fraction digits, fillzeros says to
430 * pad to two integral-seconds digits.
432 * Returns a pointer to the new end of string. No NUL terminator is put
433 * there; callers are responsible for NUL terminating str themselves.
435 * Note that any sign is stripped from the input seconds values.
438 AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
440 Assert(precision >= 0);
442 #ifdef HAVE_INT64_TIMESTAMP
443 /* fsec_t is just an int32 */
446 cp = pg_ltostr_zeropad(cp, Abs(sec), 2);
448 cp = pg_ltostr(cp, Abs(sec));
452 int32 value = Abs(fsec);
453 char *end = &cp[precision + 1];
454 bool gotnonzero = false;
459 * Append the fractional seconds part. Note that we don't want any
460 * trailing zeros here, so since we're building the number in reverse
461 * we'll skip appending zeros until we've output a non-zero digit.
465 int32 oldval = value;
469 remainder = oldval - value * 10;
471 /* check if we got a non-zero */
476 cp[precision] = '0' + remainder;
478 end = &cp[precision];
482 * If we still have a non-zero value then precision must have not been
483 * enough to print the number. We punt the problem to pg_ltostr(),
484 * which will generate a correct answer in the minimum valid width.
487 return pg_ltostr(cp, Abs(fsec));
494 /* fsec_t is a double */
499 return pg_ltostr_zeropad(cp, Abs(sec), 2);
501 return pg_ltostr(cp, Abs(sec));
506 sprintf(cp, "%0*.*f", precision + 3, precision, fabs(sec + fsec));
508 sprintf(cp, "%.*f", precision, fabs(sec + fsec));
509 return TrimTrailingZeros(cp);
511 #endif /* HAVE_INT64_TIMESTAMP */
516 * Variant of above that's specialized to timestamp case.
518 * Returns a pointer to the new end of string. No NUL terminator is put
519 * there; callers are responsible for NUL terminating str themselves.
522 AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec)
525 * In float mode, don't print fractional seconds before 1 AD, since it's
526 * unlikely there's any precision left ...
528 #ifndef HAVE_INT64_TIMESTAMP
529 if (tm->tm_year <= 0)
532 return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
536 * Multiply frac by scale (to produce seconds) and add to *tm & *fsec.
537 * We assume the input frac is less than 1 so overflow is not an issue.
540 AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
550 #ifdef HAVE_INT64_TIMESTAMP
551 *fsec += rint(frac * 1000000);
557 /* As above, but initial scale produces days */
559 AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
566 extra_days = (int) frac;
567 tm->tm_mday += extra_days;
569 AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
572 /* Fetch a fractional-second value with suitable error checking */
574 ParseFractionalSecond(char *cp, fsec_t *fsec)
578 /* Caller should always pass the start of the fraction part */
581 frac = strtod(cp, &cp);
582 /* check for parse failure */
583 if (*cp != '\0' || errno != 0)
584 return DTERR_BAD_FORMAT;
585 #ifdef HAVE_INT64_TIMESTAMP
586 *fsec = rint(frac * 1000000);
595 * Break string into tokens based on a date/time context.
596 * Returns 0 if successful, DTERR code if bogus input detected.
598 * timestr - the input string
599 * workbuf - workspace for field string storage. This must be
600 * larger than the largest legal input for this datetime type --
601 * some additional space will be needed to NUL terminate fields.
602 * buflen - the size of workbuf
603 * field[] - pointers to field strings are returned in this array
604 * ftype[] - field type indicators are returned in this array
605 * maxfields - dimensions of the above two arrays
606 * *numfields - set to the actual number of fields detected
608 * The fields extracted from the input are stored as separate,
609 * null-terminated strings in the workspace at workbuf. Any text is
610 * converted to lower case.
612 * Several field types are assigned:
613 * DTK_NUMBER - digits and (possibly) a decimal point
614 * DTK_DATE - digits and two delimiters, or digits and text
615 * DTK_TIME - digits, colon delimiters, and possibly a decimal point
616 * DTK_STRING - text (no digits or punctuation)
617 * DTK_SPECIAL - leading "+" or "-" followed by text
618 * DTK_TZ - leading "+" or "-" followed by digits (also eats ':', '.', '-')
620 * Note that some field types can hold unexpected items:
621 * DTK_NUMBER can hold date fields (yy.ddd)
622 * DTK_STRING can hold months (January) and time zones (PST)
623 * DTK_DATE can hold time zone names (America/New_York, GMT-8)
626 ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
627 char **field, int *ftype, int maxfields, int *numfields)
630 const char *cp = timestr;
631 char *bufp = workbuf;
632 const char *bufend = workbuf + buflen;
635 * Set the character pointed-to by "bufptr" to "newchar", and increment
636 * "bufptr". "end" gives the end of the buffer -- we return an error if
637 * there is no space left to append a character to the buffer. Note that
638 * "bufptr" is evaluated twice.
640 #define APPEND_CHAR(bufptr, end, newchar) \
643 if (((bufptr) + 1) >= (end)) \
644 return DTERR_BAD_FORMAT; \
645 *(bufptr)++ = newchar; \
648 /* outer loop through fields */
651 /* Ignore spaces between fields */
652 if (isspace((unsigned char) *cp))
658 /* Record start of current field */
660 return DTERR_BAD_FORMAT;
663 /* leading digit? then date or time */
664 if (isdigit((unsigned char) *cp))
666 APPEND_CHAR(bufp, bufend, *cp++);
667 while (isdigit((unsigned char) *cp))
668 APPEND_CHAR(bufp, bufend, *cp++);
673 ftype[nf] = DTK_TIME;
674 APPEND_CHAR(bufp, bufend, *cp++);
675 while (isdigit((unsigned char) *cp) ||
676 (*cp == ':') || (*cp == '.'))
677 APPEND_CHAR(bufp, bufend, *cp++);
679 /* date field? allow embedded text month */
680 else if (*cp == '-' || *cp == '/' || *cp == '.')
682 /* save delimiting character to use later */
685 APPEND_CHAR(bufp, bufend, *cp++);
686 /* second field is all digits? then no embedded text month */
687 if (isdigit((unsigned char) *cp))
689 ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
690 while (isdigit((unsigned char) *cp))
691 APPEND_CHAR(bufp, bufend, *cp++);
694 * insist that the delimiters match to get a three-field
699 ftype[nf] = DTK_DATE;
700 APPEND_CHAR(bufp, bufend, *cp++);
701 while (isdigit((unsigned char) *cp) || *cp == delim)
702 APPEND_CHAR(bufp, bufend, *cp++);
707 ftype[nf] = DTK_DATE;
708 while (isalnum((unsigned char) *cp) || *cp == delim)
709 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
714 * otherwise, number only and will determine year, month, day, or
715 * concatenated fields later...
718 ftype[nf] = DTK_NUMBER;
720 /* Leading decimal point? Then fractional seconds... */
723 APPEND_CHAR(bufp, bufend, *cp++);
724 while (isdigit((unsigned char) *cp))
725 APPEND_CHAR(bufp, bufend, *cp++);
727 ftype[nf] = DTK_NUMBER;
731 * text? then date string, month, day of week, special, or timezone
733 else if (isalpha((unsigned char) *cp))
737 ftype[nf] = DTK_STRING;
738 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
739 while (isalpha((unsigned char) *cp))
740 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
743 * Dates can have embedded '-', '/', or '.' separators. It could
744 * also be a timezone name containing embedded '/', '+', '-', '_',
745 * or ':' (but '_' or ':' can't be the first punctuation). If the
746 * next character is a digit or '+', we need to check whether what
747 * we have so far is a recognized non-timezone keyword --- if so,
748 * don't believe that this is the start of a timezone.
751 if (*cp == '-' || *cp == '/' || *cp == '.')
753 else if (*cp == '+' || isdigit((unsigned char) *cp))
755 *bufp = '\0'; /* null-terminate current field value */
756 /* we need search only the core token table, not TZ names */
757 if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
762 ftype[nf] = DTK_DATE;
765 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
766 } while (*cp == '+' || *cp == '-' ||
767 *cp == '/' || *cp == '_' ||
768 *cp == '.' || *cp == ':' ||
769 isalnum((unsigned char) *cp));
772 /* sign? then special or numeric timezone */
773 else if (*cp == '+' || *cp == '-')
775 APPEND_CHAR(bufp, bufend, *cp++);
776 /* soak up leading whitespace */
777 while (isspace((unsigned char) *cp))
779 /* numeric timezone? */
780 /* note that "DTK_TZ" could also be a signed float or yyyy-mm */
781 if (isdigit((unsigned char) *cp))
784 APPEND_CHAR(bufp, bufend, *cp++);
785 while (isdigit((unsigned char) *cp) ||
786 *cp == ':' || *cp == '.' || *cp == '-')
787 APPEND_CHAR(bufp, bufend, *cp++);
790 else if (isalpha((unsigned char) *cp))
792 ftype[nf] = DTK_SPECIAL;
793 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
794 while (isalpha((unsigned char) *cp))
795 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
797 /* otherwise something wrong... */
799 return DTERR_BAD_FORMAT;
801 /* ignore other punctuation but use as delimiter */
802 else if (ispunct((unsigned char) *cp))
807 /* otherwise, something is not right... */
809 return DTERR_BAD_FORMAT;
811 /* force in a delimiter after each field */
823 * Interpret previously parsed fields for general date and time.
824 * Return 0 if full date, 1 if only time, and negative DTERR code if problems.
825 * (Currently, all callers treat 1 as an error return too.)
827 * External format(s):
828 * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
829 * "Fri Feb-7-1997 15:23:27"
830 * "Feb-7-1997 15:23:27"
831 * "2-7-1997 15:23:27"
832 * "1997-2-7 15:23:27"
833 * "1997.038 15:23:27" (day of year 1-366)
834 * Also supports input in compact time:
837 * "20011225T040506.789-07"
839 * Use the system-provided functions to get the current time zone
840 * if not specified in the input string.
842 * If the date is outside the range of pg_time_t (in practice that could only
843 * happen if pg_time_t is just 32 bits), then assume UTC time zone - thomas
847 DecodeDateTime(char **field, int *ftype, int nf,
848 int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
853 int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */
858 bool haveTextMonth = FALSE;
859 bool isjulian = FALSE;
860 bool is2digits = FALSE;
862 pg_tz *namedTz = NULL;
863 pg_tz *abbrevTz = NULL;
869 * We'll insist on at least all of the date fields, but initialize the
870 * remaining fields in case they are not set later...
877 /* don't know daylight savings time status apriori */
882 for (i = 0; i < nf; i++)
889 * Integral julian day with attached time zone? All other
890 * forms with JD will be separated into distinct fields, so we
891 * handle just this case here.
893 if (ptype == DTK_JULIAN)
899 return DTERR_BAD_FORMAT;
902 val = strtoint(field[i], &cp, 10);
903 if (errno == ERANGE || val < 0)
904 return DTERR_FIELD_OVERFLOW;
906 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
909 /* Get the time zone from the end of the string */
910 dterr = DecodeTimezone(cp, tzp);
914 tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
920 * Already have a date? Then this might be a time zone name
921 * with embedded punctuation (e.g. "America/New_York") or a
922 * run-together time with trailing time zone (e.g. hhmmss-zz).
923 * - thomas 2001-12-25
925 * We consider it a time zone if we already have month & day.
926 * This is to allow the form "mmm dd hhmmss tz year", which
927 * we've historically accepted.
929 else if (ptype != 0 ||
930 ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==
931 (DTK_M(MONTH) | DTK_M(DAY))))
933 /* No time zone accepted? Then quit... */
935 return DTERR_BAD_FORMAT;
937 if (isdigit((unsigned char) *field[i]) || ptype != 0)
943 /* Sanity check; should not fail this test */
944 if (ptype != DTK_TIME)
945 return DTERR_BAD_FORMAT;
950 * Starts with a digit but we already have a time
951 * field? Then we are in trouble with a date and time
954 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
955 return DTERR_BAD_FORMAT;
957 if ((cp = strchr(field[i], '-')) == NULL)
958 return DTERR_BAD_FORMAT;
960 /* Get the time zone from the end of the string */
961 dterr = DecodeTimezone(cp, tzp);
967 * Then read the rest of the field as a concatenated
970 dterr = DecodeNumberField(strlen(field[i]), field[i],
978 * modify tmask after returning from
979 * DecodeNumberField()
985 namedTz = pg_tzset(field[i]);
989 * We should return an error code instead of
990 * ereport'ing directly, but then there is no way
991 * to report the bad time zone name.
994 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
995 errmsg("time zone \"%s\" not recognized",
998 /* we'll apply the zone setting below */
1004 dterr = DecodeDate(field[i], fmask,
1005 &tmask, &is2digits, tm);
1014 * This might be an ISO time following a "t" field.
1018 /* Sanity check; should not fail this test */
1019 if (ptype != DTK_TIME)
1020 return DTERR_BAD_FORMAT;
1023 dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
1029 * Check upper limit on hours; other limits checked in
1032 /* test for > 24:00:00 */
1033 if (tm->tm_hour > HOURS_PER_DAY ||
1034 (tm->tm_hour == HOURS_PER_DAY &&
1035 (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)))
1036 return DTERR_FIELD_OVERFLOW;
1044 return DTERR_BAD_FORMAT;
1046 dterr = DecodeTimezone(field[i], &tz);
1057 * Was this an "ISO date" with embedded field labels? An
1058 * example is "y2001m02d04" - thomas 2001-02-04
1066 val = strtoint(field[i], &cp, 10);
1067 if (errno == ERANGE)
1068 return DTERR_FIELD_OVERFLOW;
1071 * only a few kinds are allowed to have an embedded
1082 return DTERR_BAD_FORMAT;
1085 else if (*cp != '\0')
1086 return DTERR_BAD_FORMAT;
1092 tmask = DTK_M(YEAR);
1098 * already have a month and hour? then assume
1101 if ((fmask & DTK_M(MONTH)) != 0 &&
1102 (fmask & DTK_M(HOUR)) != 0)
1105 tmask = DTK_M(MINUTE);
1110 tmask = DTK_M(MONTH);
1121 tmask = DTK_M(HOUR);
1126 tmask = DTK_M(MINUTE);
1131 tmask = DTK_M(SECOND);
1134 dterr = ParseFractionalSecond(cp, fsec);
1137 tmask = DTK_ALL_SECS_M;
1143 dterr = DecodeTimezone(field[i], tzp);
1149 /* previous field was a label for "julian date" */
1151 return DTERR_FIELD_OVERFLOW;
1153 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1156 /* fractional Julian Day? */
1162 time = strtod(cp, &cp);
1163 if (*cp != '\0' || errno != 0)
1164 return DTERR_BAD_FORMAT;
1166 #ifdef HAVE_INT64_TIMESTAMP
1167 time *= USECS_PER_DAY;
1169 time *= SECS_PER_DAY;
1172 &tm->tm_hour, &tm->tm_min,
1174 tmask |= DTK_TIME_M;
1179 /* previous field was "t" for ISO time */
1180 dterr = DecodeNumberField(strlen(field[i]), field[i],
1181 (fmask | DTK_DATE_M),
1186 if (tmask != DTK_TIME_M)
1187 return DTERR_BAD_FORMAT;
1191 return DTERR_BAD_FORMAT;
1203 flen = strlen(field[i]);
1204 cp = strchr(field[i], '.');
1206 /* Embedded decimal and no date yet? */
1207 if (cp != NULL && !(fmask & DTK_DATE_M))
1209 dterr = DecodeDate(field[i], fmask,
1210 &tmask, &is2digits, tm);
1214 /* embedded decimal and several digits before? */
1215 else if (cp != NULL && flen - strlen(cp) > 2)
1218 * Interpret as a concatenated date or time Set the
1219 * type field to allow decoding other fields later.
1220 * Example: 20011223 or 040506
1222 dterr = DecodeNumberField(flen, field[i], fmask,
1230 * Is this a YMD or HMS specification, or a year number?
1231 * YMD and HMS are required to be six digits or more, so
1232 * if it is 5 digits, it is a year. If it is six or more
1233 * more digits, we assume it is YMD or HMS unless no date
1234 * and no time values have been specified. This forces 6+
1235 * digit years to be at the end of the string, or to use
1236 * the ISO date specification.
1238 else if (flen >= 6 && (!(fmask & DTK_DATE_M) ||
1239 !(fmask & DTK_TIME_M)))
1241 dterr = DecodeNumberField(flen, field[i], fmask,
1247 /* otherwise it is a single date/time field... */
1250 dterr = DecodeNumber(flen, field[i],
1251 haveTextMonth, fmask,
1262 /* timezone abbrevs take precedence over built-in tokens */
1263 type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
1264 if (type == UNKNOWN_FIELD)
1265 type = DecodeSpecial(i, field[i], &val);
1266 if (type == IGNORE_DTF)
1269 tmask = DTK_M(type);
1277 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1278 errmsg("date/time value \"current\" is no longer supported")));
1280 return DTERR_BAD_FORMAT;
1284 tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
1286 GetCurrentTimeUsec(tm, fsec, tzp);
1292 GetCurrentDateTime(&cur_tm);
1293 j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) - 1,
1294 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1300 GetCurrentDateTime(&cur_tm);
1301 tm->tm_year = cur_tm.tm_year;
1302 tm->tm_mon = cur_tm.tm_mon;
1303 tm->tm_mday = cur_tm.tm_mday;
1309 GetCurrentDateTime(&cur_tm);
1310 j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) + 1,
1311 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1315 tmask = (DTK_TIME_M | DTK_M(TZ));
1333 * already have a (numeric) month? then see if we can
1336 if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
1337 !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&
1340 tm->tm_mday = tm->tm_mon;
1343 haveTextMonth = TRUE;
1350 * daylight savings time modifier (solves "MET DST"
1353 tmask |= DTK_M(DTZ);
1356 return DTERR_BAD_FORMAT;
1363 * set mask for TZ here _or_ check for DTZ later when
1364 * getting default timezone
1369 return DTERR_BAD_FORMAT;
1376 return DTERR_BAD_FORMAT;
1383 return DTERR_BAD_FORMAT;
1384 /* we'll determine the actual offset later */
1409 * This is a filler field "t" indicating that the next
1410 * field is time. Try to verify that this is sensible.
1414 /* No preceding date? Then quit... */
1415 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1416 return DTERR_BAD_FORMAT;
1419 * We will need one of the following fields:
1420 * DTK_NUMBER should be hhmmss.fff
1421 * DTK_TIME should be hh:mm:ss.fff
1422 * DTK_DATE should be hhmmss-zz
1425 (ftype[i + 1] != DTK_NUMBER &&
1426 ftype[i + 1] != DTK_TIME &&
1427 ftype[i + 1] != DTK_DATE))
1428 return DTERR_BAD_FORMAT;
1436 * Before giving up and declaring error, check to see
1437 * if it is an all-alpha timezone name.
1439 namedTz = pg_tzset(field[i]);
1441 return DTERR_BAD_FORMAT;
1442 /* we'll apply the zone setting below */
1447 return DTERR_BAD_FORMAT;
1452 return DTERR_BAD_FORMAT;
1456 return DTERR_BAD_FORMAT;
1458 } /* end loop over fields */
1460 /* do final checking/adjustment of Y/M/D fields */
1461 dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
1466 if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
1467 return DTERR_FIELD_OVERFLOW;
1468 if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
1470 else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
1471 tm->tm_hour += HOURS_PER_DAY / 2;
1473 /* do additional checking for full date specs... */
1474 if (*dtype == DTK_DATE)
1476 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1478 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1480 return DTERR_BAD_FORMAT;
1484 * If we had a full timezone spec, compute the offset (we could not do
1485 * it before, because we need the date to resolve DST status).
1487 if (namedTz != NULL)
1489 /* daylight savings time modifier disallowed with full TZ */
1490 if (fmask & DTK_M(DTZMOD))
1491 return DTERR_BAD_FORMAT;
1493 *tzp = DetermineTimeZoneOffset(tm, namedTz);
1497 * Likewise, if we had a dynamic timezone abbreviation, resolve it
1500 if (abbrevTz != NULL)
1502 /* daylight savings time modifier disallowed with dynamic TZ */
1503 if (fmask & DTK_M(DTZMOD))
1504 return DTERR_BAD_FORMAT;
1506 *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz);
1509 /* timezone not specified? then use session timezone */
1510 if (tzp != NULL && !(fmask & DTK_M(TZ)))
1513 * daylight savings time modifier but no standard timezone? then
1516 if (fmask & DTK_M(DTZMOD))
1517 return DTERR_BAD_FORMAT;
1519 *tzp = DetermineTimeZoneOffset(tm, session_timezone);
1527 /* DetermineTimeZoneOffset()
1529 * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min,
1530 * and tm_sec fields are set, and a zic-style time zone definition, determine
1531 * the applicable GMT offset and daylight-savings status at that time.
1532 * Set the struct pg_tm's tm_isdst field accordingly, and return the GMT
1533 * offset as the function result.
1535 * Note: if the date is out of the range we can deal with, we return zero
1536 * as the GMT offset and set tm_isdst = 0. We don't throw an error here,
1537 * though probably some higher-level code will.
1540 DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp)
1544 return DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1548 /* DetermineTimeZoneOffsetInternal()
1550 * As above, but also return the actual UTC time imputed to the date/time
1553 * In event of an out-of-range date, we punt by returning zero into *tp.
1554 * This is okay for the immediate callers but is a good reason for not
1555 * exposing this worker function globally.
1557 * Note: it might seem that we should use mktime() for this, but bitter
1558 * experience teaches otherwise. This code is much faster than most versions
1559 * of mktime(), anyway.
1562 DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp)
1572 long int before_gmtoff,
1579 * First, generate the pg_time_t value corresponding to the given
1580 * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1581 * timezone is GMT. (For a valid Julian date, integer overflow should be
1582 * impossible with 64-bit pg_time_t, but let's check for safety.)
1584 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1586 date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
1588 day = ((pg_time_t) date) * SECS_PER_DAY;
1589 if (day / SECS_PER_DAY != date)
1591 sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;
1593 /* since sec >= 0, overflow could only be from +day to -mytime */
1594 if (mytime < 0 && day > 0)
1598 * Find the DST time boundary just before or following the target time. We
1599 * assume that all zones have GMT offsets less than 24 hours, and that DST
1600 * boundaries can't be closer together than 48 hours, so backing up 24
1601 * hours and finding the "next" boundary will work.
1603 prevtime = mytime - SECS_PER_DAY;
1604 if (mytime < 0 && prevtime > 0)
1607 res = pg_next_dst_boundary(&prevtime,
1608 &before_gmtoff, &before_isdst,
1610 &after_gmtoff, &after_isdst,
1613 goto overflow; /* failure? */
1617 /* Non-DST zone, life is simple */
1618 tm->tm_isdst = before_isdst;
1619 *tp = mytime - before_gmtoff;
1620 return -(int) before_gmtoff;
1624 * Form the candidate pg_time_t values with local-time adjustment
1626 beforetime = mytime - before_gmtoff;
1627 if ((before_gmtoff > 0 &&
1628 mytime < 0 && beforetime > 0) ||
1629 (before_gmtoff <= 0 &&
1630 mytime > 0 && beforetime < 0))
1632 aftertime = mytime - after_gmtoff;
1633 if ((after_gmtoff > 0 &&
1634 mytime < 0 && aftertime > 0) ||
1635 (after_gmtoff <= 0 &&
1636 mytime > 0 && aftertime < 0))
1640 * If both before or both after the boundary time, we know what to do. The
1641 * boundary time itself is considered to be after the transition, which
1642 * means we can accept aftertime == boundary in the second case.
1644 if (beforetime < boundary && aftertime < boundary)
1646 tm->tm_isdst = before_isdst;
1648 return -(int) before_gmtoff;
1650 if (beforetime > boundary && aftertime >= boundary)
1652 tm->tm_isdst = after_isdst;
1654 return -(int) after_gmtoff;
1658 * It's an invalid or ambiguous time due to timezone transition. In a
1659 * spring-forward transition, prefer the "before" interpretation; in a
1660 * fall-back transition, prefer "after". (We used to define and implement
1661 * this test as "prefer the standard-time interpretation", but that rule
1662 * does not help to resolve the behavior when both times are reported as
1663 * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
1665 if (beforetime > aftertime)
1667 tm->tm_isdst = before_isdst;
1669 return -(int) before_gmtoff;
1671 tm->tm_isdst = after_isdst;
1673 return -(int) after_gmtoff;
1676 /* Given date is out of range, so assume UTC */
1683 /* DetermineTimeZoneAbbrevOffset()
1685 * Determine the GMT offset and DST flag to be attributed to a dynamic
1686 * time zone abbreviation, that is one whose meaning has changed over time.
1687 * *tm contains the local time at which the meaning should be determined,
1688 * and tm->tm_isdst receives the DST flag.
1690 * This differs from the behavior of DetermineTimeZoneOffset() in that a
1691 * standard-time or daylight-time abbreviation forces use of the corresponding
1692 * GMT offset even when the zone was then in DS or standard time respectively.
1693 * (However, that happens only if we can match the given abbreviation to some
1694 * abbreviation that appears in the IANA timezone data. Otherwise, we fall
1695 * back to doing DetermineTimeZoneOffset().)
1698 DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp)
1706 * Compute the UTC time we want to probe at. (In event of overflow, we'll
1707 * probe at the epoch, which is a bit random but probably doesn't matter.)
1709 zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1712 * Try to match the abbreviation to something in the zone definition.
1714 if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1715 &abbr_offset, &abbr_isdst))
1717 /* Success, so use the abbrev-specific answers. */
1718 tm->tm_isdst = abbr_isdst;
1723 * No match, so use the answers we already got from
1724 * DetermineTimeZoneOffsetInternal.
1730 /* DetermineTimeZoneAbbrevOffsetTS()
1732 * As above but the probe time is specified as a TimestampTz (hence, UTC time),
1733 * and DST status is returned into *isdst rather than into tm->tm_isdst.
1736 DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr,
1737 pg_tz *tzp, int *isdst)
1739 pg_time_t t = timestamptz_to_time_t(ts);
1747 * If the abbrev matches anything in the zone data, this is pretty easy.
1749 if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1750 &abbr_offset, isdst))
1754 * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1756 if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1758 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1759 errmsg("timestamp out of range")));
1761 zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1762 *isdst = tm.tm_isdst;
1767 /* DetermineTimeZoneAbbrevOffsetInternal()
1769 * Workhorse for above two functions: work from a pg_time_t probe instant.
1770 * On success, return GMT offset and DST status into *offset and *isdst.
1773 DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp,
1774 int *offset, int *isdst)
1776 char upabbr[TZ_STRLEN_MAX + 1];
1780 /* We need to force the abbrev to upper case */
1781 strlcpy(upabbr, abbr, sizeof(upabbr));
1782 for (p = (unsigned char *) upabbr; *p; p++)
1783 *p = pg_toupper(*p);
1785 /* Look up the abbrev's meaning at this time in this zone */
1786 if (pg_interpret_timezone_abbrev(upabbr,
1792 /* Change sign to agree with DetermineTimeZoneOffset() */
1793 *offset = (int) -gmtoff;
1801 * Interpret parsed string as time fields only.
1802 * Returns 0 if successful, DTERR code if bogus input detected.
1804 * Note that support for time zone is here for
1805 * SQL TIME WITH TIME ZONE, but it reveals
1806 * bogosity with SQL date/time standards, since
1807 * we must infer a time zone from current time.
1808 * - thomas 2000-03-10
1809 * Allow specifying date to get a better time zone,
1810 * if time zones are allowed. - thomas 2001-12-26
1813 DecodeTimeOnly(char **field, int *ftype, int nf,
1814 int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
1819 int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */
1823 bool isjulian = FALSE;
1824 bool is2digits = FALSE;
1827 pg_tz *namedTz = NULL;
1828 pg_tz *abbrevTz = NULL;
1829 char *abbrev = NULL;
1837 /* don't know daylight savings time status apriori */
1843 for (i = 0; i < nf; i++)
1850 * Time zone not allowed? Then should not accept dates or time
1851 * zones no matter what else!
1854 return DTERR_BAD_FORMAT;
1856 /* Under limited circumstances, we will accept a date... */
1857 if (i == 0 && nf >= 2 &&
1858 (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
1860 dterr = DecodeDate(field[i], fmask,
1861 &tmask, &is2digits, tm);
1865 /* otherwise, this is a time and/or time zone */
1868 if (isdigit((unsigned char) *field[i]))
1873 * Starts with a digit but we already have a time
1874 * field? Then we are in trouble with time already...
1876 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1877 return DTERR_BAD_FORMAT;
1880 * Should not get here and fail. Sanity check only...
1882 if ((cp = strchr(field[i], '-')) == NULL)
1883 return DTERR_BAD_FORMAT;
1885 /* Get the time zone from the end of the string */
1886 dterr = DecodeTimezone(cp, tzp);
1892 * Then read the rest of the field as a concatenated
1895 dterr = DecodeNumberField(strlen(field[i]), field[i],
1896 (fmask | DTK_DATE_M),
1907 namedTz = pg_tzset(field[i]);
1911 * We should return an error code instead of
1912 * ereport'ing directly, but then there is no way
1913 * to report the bad time zone name.
1916 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1917 errmsg("time zone \"%s\" not recognized",
1920 /* we'll apply the zone setting below */
1928 dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
1929 INTERVAL_FULL_RANGE,
1940 return DTERR_BAD_FORMAT;
1942 dterr = DecodeTimezone(field[i], &tz);
1953 * Was this an "ISO time" with embedded field labels? An
1954 * example is "h04m05s06" - thomas 2001-02-04
1961 /* Only accept a date under limited circumstances */
1969 return DTERR_BAD_FORMAT;
1975 val = strtoint(field[i], &cp, 10);
1976 if (errno == ERANGE)
1977 return DTERR_FIELD_OVERFLOW;
1980 * only a few kinds are allowed to have an embedded
1991 return DTERR_BAD_FORMAT;
1994 else if (*cp != '\0')
1995 return DTERR_BAD_FORMAT;
2001 tmask = DTK_M(YEAR);
2007 * already have a month and hour? then assume
2010 if ((fmask & DTK_M(MONTH)) != 0 &&
2011 (fmask & DTK_M(HOUR)) != 0)
2014 tmask = DTK_M(MINUTE);
2019 tmask = DTK_M(MONTH);
2030 tmask = DTK_M(HOUR);
2035 tmask = DTK_M(MINUTE);
2040 tmask = DTK_M(SECOND);
2043 dterr = ParseFractionalSecond(cp, fsec);
2046 tmask = DTK_ALL_SECS_M;
2052 dterr = DecodeTimezone(field[i], tzp);
2058 /* previous field was a label for "julian date" */
2060 return DTERR_FIELD_OVERFLOW;
2062 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2070 time = strtod(cp, &cp);
2071 if (*cp != '\0' || errno != 0)
2072 return DTERR_BAD_FORMAT;
2074 #ifdef HAVE_INT64_TIMESTAMP
2075 time *= USECS_PER_DAY;
2077 time *= SECS_PER_DAY;
2080 &tm->tm_hour, &tm->tm_min,
2082 tmask |= DTK_TIME_M;
2087 /* previous field was "t" for ISO time */
2088 dterr = DecodeNumberField(strlen(field[i]), field[i],
2089 (fmask | DTK_DATE_M),
2096 if (tmask != DTK_TIME_M)
2097 return DTERR_BAD_FORMAT;
2101 return DTERR_BAD_FORMAT;
2113 flen = strlen(field[i]);
2114 cp = strchr(field[i], '.');
2116 /* Embedded decimal? */
2120 * Under limited circumstances, we will accept a
2123 if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
2125 dterr = DecodeDate(field[i], fmask,
2126 &tmask, &is2digits, tm);
2130 /* embedded decimal and several digits before? */
2131 else if (flen - strlen(cp) > 2)
2134 * Interpret as a concatenated date or time Set
2135 * the type field to allow decoding other fields
2136 * later. Example: 20011223 or 040506
2138 dterr = DecodeNumberField(flen, field[i],
2139 (fmask | DTK_DATE_M),
2147 return DTERR_BAD_FORMAT;
2151 dterr = DecodeNumberField(flen, field[i],
2152 (fmask | DTK_DATE_M),
2159 /* otherwise it is a single date/time field... */
2162 dterr = DecodeNumber(flen, field[i],
2164 (fmask | DTK_DATE_M),
2175 /* timezone abbrevs take precedence over built-in tokens */
2176 type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
2177 if (type == UNKNOWN_FIELD)
2178 type = DecodeSpecial(i, field[i], &val);
2179 if (type == IGNORE_DTF)
2182 tmask = DTK_M(type);
2190 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2191 errmsg("date/time value \"current\" is no longer supported")));
2192 return DTERR_BAD_FORMAT;
2198 GetCurrentTimeUsec(tm, fsec, NULL);
2202 tmask = (DTK_TIME_M | DTK_M(TZ));
2211 return DTERR_BAD_FORMAT;
2219 * daylight savings time modifier (solves "MET DST"
2222 tmask |= DTK_M(DTZ);
2225 return DTERR_BAD_FORMAT;
2232 * set mask for TZ here _or_ check for DTZ later when
2233 * getting default timezone
2238 return DTERR_BAD_FORMAT;
2246 return DTERR_BAD_FORMAT;
2254 return DTERR_BAD_FORMAT;
2255 /* we'll determine the actual offset later */
2278 * We will need one of the following fields:
2279 * DTK_NUMBER should be hhmmss.fff
2280 * DTK_TIME should be hh:mm:ss.fff
2281 * DTK_DATE should be hhmmss-zz
2284 (ftype[i + 1] != DTK_NUMBER &&
2285 ftype[i + 1] != DTK_TIME &&
2286 ftype[i + 1] != DTK_DATE))
2287 return DTERR_BAD_FORMAT;
2295 * Before giving up and declaring error, check to see
2296 * if it is an all-alpha timezone name.
2298 namedTz = pg_tzset(field[i]);
2300 return DTERR_BAD_FORMAT;
2301 /* we'll apply the zone setting below */
2306 return DTERR_BAD_FORMAT;
2311 return DTERR_BAD_FORMAT;
2315 return DTERR_BAD_FORMAT;
2317 } /* end loop over fields */
2319 /* do final checking/adjustment of Y/M/D fields */
2320 dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
2325 if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
2326 return DTERR_FIELD_OVERFLOW;
2327 if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
2329 else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
2330 tm->tm_hour += HOURS_PER_DAY / 2;
2333 * This should match the checks in make_timestamp_internal
2335 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2336 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2337 tm->tm_hour > HOURS_PER_DAY ||
2338 /* test for > 24:00:00 */
2339 (tm->tm_hour == HOURS_PER_DAY &&
2340 (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)) ||
2341 #ifdef HAVE_INT64_TIMESTAMP
2342 *fsec < INT64CONST(0) || *fsec > USECS_PER_SEC
2344 *fsec < 0 || *fsec > 1
2347 return DTERR_FIELD_OVERFLOW;
2349 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2350 return DTERR_BAD_FORMAT;
2353 * If we had a full timezone spec, compute the offset (we could not do it
2354 * before, because we may need the date to resolve DST status).
2356 if (namedTz != NULL)
2360 /* daylight savings time modifier disallowed with full TZ */
2361 if (fmask & DTK_M(DTZMOD))
2362 return DTERR_BAD_FORMAT;
2364 /* if non-DST zone, we do not need to know the date */
2365 if (pg_get_timezone_offset(namedTz, &gmtoff))
2367 *tzp = -(int) gmtoff;
2371 /* a date has to be specified */
2372 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2373 return DTERR_BAD_FORMAT;
2374 *tzp = DetermineTimeZoneOffset(tm, namedTz);
2379 * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
2381 if (abbrevTz != NULL)
2387 * daylight savings time modifier but no standard timezone? then error
2389 if (fmask & DTK_M(DTZMOD))
2390 return DTERR_BAD_FORMAT;
2392 if ((fmask & DTK_DATE_M) == 0)
2393 GetCurrentDateTime(tmp);
2396 tmp->tm_year = tm->tm_year;
2397 tmp->tm_mon = tm->tm_mon;
2398 tmp->tm_mday = tm->tm_mday;
2400 tmp->tm_hour = tm->tm_hour;
2401 tmp->tm_min = tm->tm_min;
2402 tmp->tm_sec = tm->tm_sec;
2403 *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
2404 tm->tm_isdst = tmp->tm_isdst;
2407 /* timezone not specified? then use session timezone */
2408 if (tzp != NULL && !(fmask & DTK_M(TZ)))
2414 * daylight savings time modifier but no standard timezone? then error
2416 if (fmask & DTK_M(DTZMOD))
2417 return DTERR_BAD_FORMAT;
2419 if ((fmask & DTK_DATE_M) == 0)
2420 GetCurrentDateTime(tmp);
2423 tmp->tm_year = tm->tm_year;
2424 tmp->tm_mon = tm->tm_mon;
2425 tmp->tm_mday = tm->tm_mday;
2427 tmp->tm_hour = tm->tm_hour;
2428 tmp->tm_min = tm->tm_min;
2429 tmp->tm_sec = tm->tm_sec;
2430 *tzp = DetermineTimeZoneOffset(tmp, session_timezone);
2431 tm->tm_isdst = tmp->tm_isdst;
2438 * Decode date string which includes delimiters.
2439 * Return 0 if okay, a DTERR code if not.
2441 * str: field to be parsed
2442 * fmask: bitmask for field types already seen
2443 * *tmask: receives bitmask for fields found here
2444 * *is2digits: set to TRUE if we find 2-digit year
2445 * *tm: field values are stored into appropriate members of this struct
2448 DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
2456 bool haveTextMonth = FALSE;
2460 char *field[MAXDATEFIELDS];
2464 /* parse this string... */
2465 while (*str != '\0' && nf < MAXDATEFIELDS)
2467 /* skip field separators */
2468 while (*str != '\0' && !isalnum((unsigned char) *str))
2472 return DTERR_BAD_FORMAT; /* end of string after separator */
2475 if (isdigit((unsigned char) *str))
2477 while (isdigit((unsigned char) *str))
2480 else if (isalpha((unsigned char) *str))
2482 while (isalpha((unsigned char) *str))
2486 /* Just get rid of any non-digit, non-alpha characters... */
2492 /* look first for text fields, since that will be unambiguous month */
2493 for (i = 0; i < nf; i++)
2495 if (isalpha((unsigned char) *field[i]))
2497 type = DecodeSpecial(i, field[i], &val);
2498 if (type == IGNORE_DTF)
2501 dmask = DTK_M(type);
2506 haveTextMonth = TRUE;
2510 return DTERR_BAD_FORMAT;
2513 return DTERR_BAD_FORMAT;
2518 /* mark this field as being completed */
2523 /* now pick up remaining numeric fields */
2524 for (i = 0; i < nf; i++)
2526 if (field[i] == NULL)
2529 if ((len = strlen(field[i])) <= 0)
2530 return DTERR_BAD_FORMAT;
2532 dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2539 return DTERR_BAD_FORMAT;
2545 if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2546 return DTERR_BAD_FORMAT;
2548 /* validation of the field values must wait until ValidateDate() */
2554 * Check valid year/month/day values, handle BC and DOY cases
2555 * Return 0 if okay, a DTERR code if not.
2558 ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
2561 if (fmask & DTK_M(YEAR))
2565 /* tm_year is correct and should not be touched */
2569 /* there is no year zero in AD/BC notation */
2570 if (tm->tm_year <= 0)
2571 return DTERR_FIELD_OVERFLOW;
2572 /* internally, we represent 1 BC as year zero, 2 BC as -1, etc */
2573 tm->tm_year = -(tm->tm_year - 1);
2577 /* process 1 or 2-digit input as 1970-2069 AD, allow '0' and '00' */
2578 if (tm->tm_year < 0) /* just paranoia */
2579 return DTERR_FIELD_OVERFLOW;
2580 if (tm->tm_year < 70)
2581 tm->tm_year += 2000;
2582 else if (tm->tm_year < 100)
2583 tm->tm_year += 1900;
2587 /* there is no year zero in AD/BC notation */
2588 if (tm->tm_year <= 0)
2589 return DTERR_FIELD_OVERFLOW;
2593 /* now that we have correct year, decode DOY */
2594 if (fmask & DTK_M(DOY))
2596 j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
2597 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2600 /* check for valid month */
2601 if (fmask & DTK_M(MONTH))
2603 if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
2604 return DTERR_MD_FIELD_OVERFLOW;
2607 /* minimal check for valid day */
2608 if (fmask & DTK_M(DAY))
2610 if (tm->tm_mday < 1 || tm->tm_mday > 31)
2611 return DTERR_MD_FIELD_OVERFLOW;
2614 if ((fmask & DTK_DATE_M) == DTK_DATE_M)
2617 * Check for valid day of month, now that we know for sure the month
2618 * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
2619 * unlikely that "Feb 29" is a YMD-order error.
2621 if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2622 return DTERR_FIELD_OVERFLOW;
2630 * Decode time string which includes delimiters.
2631 * Return 0 if okay, a DTERR code if not.
2633 * Only check the lower limit on hours, since this same code can be
2634 * used to represent time spans.
2637 DecodeTime(char *str, int fmask, int range,
2638 int *tmask, struct pg_tm * tm, fsec_t *fsec)
2643 *tmask = DTK_TIME_M;
2646 tm->tm_hour = strtoint(str, &cp, 10);
2647 if (errno == ERANGE)
2648 return DTERR_FIELD_OVERFLOW;
2650 return DTERR_BAD_FORMAT;
2652 tm->tm_min = strtoint(cp + 1, &cp, 10);
2653 if (errno == ERANGE)
2654 return DTERR_FIELD_OVERFLOW;
2659 /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2660 if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND)))
2662 tm->tm_sec = tm->tm_min;
2663 tm->tm_min = tm->tm_hour;
2667 else if (*cp == '.')
2669 /* always assume mm:ss.sss is MINUTE TO SECOND */
2670 dterr = ParseFractionalSecond(cp, fsec);
2673 tm->tm_sec = tm->tm_min;
2674 tm->tm_min = tm->tm_hour;
2677 else if (*cp == ':')
2680 tm->tm_sec = strtoint(cp + 1, &cp, 10);
2681 if (errno == ERANGE)
2682 return DTERR_FIELD_OVERFLOW;
2685 else if (*cp == '.')
2687 dterr = ParseFractionalSecond(cp, fsec);
2692 return DTERR_BAD_FORMAT;
2695 return DTERR_BAD_FORMAT;
2697 /* do a sanity check */
2698 #ifdef HAVE_INT64_TIMESTAMP
2699 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2700 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2701 *fsec < INT64CONST(0) ||
2702 *fsec > USECS_PER_SEC)
2703 return DTERR_FIELD_OVERFLOW;
2705 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2706 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2707 *fsec < 0 || *fsec > 1)
2708 return DTERR_FIELD_OVERFLOW;
2716 * Interpret plain numeric field as a date value in context.
2717 * Return 0 if okay, a DTERR code if not.
2720 DecodeNumber(int flen, char *str, bool haveTextMonth, int fmask,
2721 int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
2730 val = strtoint(str, &cp, 10);
2731 if (errno == ERANGE)
2732 return DTERR_FIELD_OVERFLOW;
2734 return DTERR_BAD_FORMAT;
2739 * More than two digits before decimal point? Then could be a date or
2740 * a run-together time: 2001.360 20011225 040506.789
2744 dterr = DecodeNumberField(flen, str,
2745 (fmask | DTK_DATE_M),
2753 dterr = ParseFractionalSecond(cp, fsec);
2757 else if (*cp != '\0')
2758 return DTERR_BAD_FORMAT;
2760 /* Special case for day of year */
2761 if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
2764 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
2766 /* tm_mon and tm_mday can't actually be set yet ... */
2770 /* Switch based on what we have so far */
2771 switch (fmask & DTK_DATE_M)
2776 * Nothing so far; make a decision about what we think the input
2777 * is. There used to be lots of heuristics here, but the
2778 * consensus now is to be paranoid. It *must* be either
2779 * YYYY-MM-DD (with a more-than-two-digit year field), or the
2780 * field order defined by DateOrder.
2782 if (flen >= 3 || DateOrder == DATEORDER_YMD)
2784 *tmask = DTK_M(YEAR);
2787 else if (DateOrder == DATEORDER_DMY)
2789 *tmask = DTK_M(DAY);
2794 *tmask = DTK_M(MONTH);
2800 /* Must be at second field of YY-MM-DD */
2801 *tmask = DTK_M(MONTH);
2805 case (DTK_M(MONTH)):
2809 * We are at the first numeric field of a date that included a
2810 * textual month name. We want to support the variants
2811 * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous
2812 * inputs. We will also accept MON-DD-YY or DD-MON-YY in
2813 * either DMY or MDY modes, as well as YY-MON-DD in YMD mode.
2815 if (flen >= 3 || DateOrder == DATEORDER_YMD)
2817 *tmask = DTK_M(YEAR);
2822 *tmask = DTK_M(DAY);
2828 /* Must be at second field of MM-DD-YY */
2829 *tmask = DTK_M(DAY);
2834 case (DTK_M(YEAR) | DTK_M(MONTH)):
2837 /* Need to accept DD-MON-YYYY even in YMD mode */
2838 if (flen >= 3 && *is2digits)
2840 /* Guess that first numeric field is day was wrong */
2841 *tmask = DTK_M(DAY); /* YEAR is already set */
2842 tm->tm_mday = tm->tm_year;
2848 *tmask = DTK_M(DAY);
2854 /* Must be at third field of YY-MM-DD */
2855 *tmask = DTK_M(DAY);
2861 /* Must be at second field of DD-MM-YY */
2862 *tmask = DTK_M(MONTH);
2866 case (DTK_M(MONTH) | DTK_M(DAY)):
2867 /* Must be at third field of DD-MM-YY or MM-DD-YY */
2868 *tmask = DTK_M(YEAR);
2872 case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
2873 /* we have all the date, so it must be a time field */
2874 dterr = DecodeNumberField(flen, str, fmask,
2882 /* Anything else is bogus input */
2883 return DTERR_BAD_FORMAT;
2887 * When processing a year field, mark it for adjustment if it's only one
2890 if (*tmask == DTK_M(YEAR))
2891 *is2digits = (flen <= 2);
2897 /* DecodeNumberField()
2898 * Interpret numeric string as a concatenated date or time field.
2899 * Return a DTK token (>= 0) if successful, a DTERR code (< 0) if not.
2901 * Use the context of previously decoded fields to help with
2902 * the interpretation.
2905 DecodeNumberField(int len, char *str, int fmask,
2906 int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
2911 * Have a decimal point? Then this is a date or something with a seconds
2914 if ((cp = strchr(str, '.')) != NULL)
2917 * Can we use ParseFractionalSecond here? Not clear whether trailing
2918 * junk should be rejected ...
2923 frac = strtod(cp, NULL);
2925 return DTERR_BAD_FORMAT;
2926 #ifdef HAVE_INT64_TIMESTAMP
2927 *fsec = rint(frac * 1000000);
2931 /* Now truncate off the fraction for further processing */
2935 /* No decimal point and no complete date yet? */
2936 else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2940 *tmask = DTK_DATE_M;
2943 * Start from end and consider first 2 as Day, next 2 as Month,
2944 * and the rest as Year.
2946 tm->tm_mday = atoi(str + (len - 2));
2947 *(str + (len - 2)) = '\0';
2948 tm->tm_mon = atoi(str + (len - 4));
2949 *(str + (len - 4)) = '\0';
2950 tm->tm_year = atoi(str);
2958 /* not all time fields are specified? */
2959 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2964 *tmask = DTK_TIME_M;
2965 tm->tm_sec = atoi(str + 4);
2967 tm->tm_min = atoi(str + 2);
2969 tm->tm_hour = atoi(str);
2976 *tmask = DTK_TIME_M;
2978 tm->tm_min = atoi(str + 2);
2980 tm->tm_hour = atoi(str);
2986 return DTERR_BAD_FORMAT;
2991 * Interpret string as a numeric timezone.
2993 * Return 0 if okay (and set *tzp), a DTERR code if not okay.
2996 DecodeTimezone(char *str, int *tzp)
3004 /* leading character must be "+" or "-" */
3005 if (*str != '+' && *str != '-')
3006 return DTERR_BAD_FORMAT;
3009 hr = strtoint(str + 1, &cp, 10);
3010 if (errno == ERANGE)
3011 return DTERR_TZDISP_OVERFLOW;
3013 /* explicit delimiter? */
3017 min = strtoint(cp + 1, &cp, 10);
3018 if (errno == ERANGE)
3019 return DTERR_TZDISP_OVERFLOW;
3023 sec = strtoint(cp + 1, &cp, 10);
3024 if (errno == ERANGE)
3025 return DTERR_TZDISP_OVERFLOW;
3028 /* otherwise, might have run things together... */
3029 else if (*cp == '\0' && strlen(str) > 3)
3033 /* we could, but don't, support a run-together hhmmss format */
3038 /* Range-check the values; see notes in datatype/timestamp.h */
3039 if (hr < 0 || hr > MAX_TZDISP_HOUR)
3040 return DTERR_TZDISP_OVERFLOW;
3041 if (min < 0 || min >= MINS_PER_HOUR)
3042 return DTERR_TZDISP_OVERFLOW;
3043 if (sec < 0 || sec >= SECS_PER_MINUTE)
3044 return DTERR_TZDISP_OVERFLOW;
3046 tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
3053 return DTERR_BAD_FORMAT;
3059 /* DecodeTimezoneAbbrev()
3060 * Interpret string as a timezone abbreviation, if possible.
3062 * Returns an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
3063 * string is not any known abbreviation. On success, set *offset and *tz to
3064 * represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
3065 * Note that full timezone names (such as America/New_York) are not handled
3066 * here, mostly for historical reasons.
3068 * Given string must be lowercased already.
3070 * Implement a cache lookup since it is likely that dates
3071 * will be related in format.
3074 DecodeTimezoneAbbrev(int field, char *lowtoken,
3075 int *offset, pg_tz **tz)
3080 tp = abbrevcache[field];
3081 /* use strncmp so that we match truncated tokens */
3082 if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3085 tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
3086 zoneabbrevtbl->numabbrevs);
3092 type = UNKNOWN_FIELD;
3098 abbrevcache[field] = tp;
3103 *tz = FetchDynamicTimeZone(zoneabbrevtbl, tp);
3107 *offset = tp->value;
3117 * Decode text string using lookup table.
3119 * Recognizes the keywords listed in datetktbl.
3120 * Note: at one time this would also recognize timezone abbreviations,
3121 * but no more; use DecodeTimezoneAbbrev for that.
3123 * Given string must be lowercased already.
3125 * Implement a cache lookup since it is likely that dates
3126 * will be related in format.
3129 DecodeSpecial(int field, char *lowtoken, int *val)
3134 tp = datecache[field];
3135 /* use strncmp so that we match truncated tokens */
3136 if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3138 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3142 type = UNKNOWN_FIELD;
3147 datecache[field] = tp;
3158 * Zero out a pg_tm and associated fsec_t
3161 ClearPgTm(struct pg_tm * tm, fsec_t *fsec)
3174 * Interpret previously parsed fields for general time interval.
3175 * Returns 0 if successful, DTERR code if bogus input detected.
3176 * dtype, tm, fsec are output parameters.
3178 * Allow "date" field DTK_DATE since this could be just
3179 * an unsigned floating point number. - thomas 1997-11-16
3181 * Allow ISO-style time span, with implicit units on number of days
3182 * preceding an hh:mm:ss field. - thomas 1998-04-30
3185 DecodeInterval(char **field, int *ftype, int nf, int range,
3186 int *dtype, struct pg_tm * tm, fsec_t *fsec)
3188 bool is_before = FALSE;
3200 ClearPgTm(tm, fsec);
3202 /* read through list backwards to pick up units before values */
3203 for (i = nf - 1; i >= 0; i--)
3208 dterr = DecodeTime(field[i], fmask, range,
3218 * Timezone means a token with a leading sign character and at
3219 * least one digit; there could be ':', '.', '-' embedded in
3222 Assert(*field[i] == '-' || *field[i] == '+');
3225 * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3226 * like DTK_TIME case above, plus handling the sign.
3228 if (strchr(field[i] + 1, ':') != NULL &&
3229 DecodeTime(field[i] + 1, fmask, range,
3230 &tmask, tm, fsec) == 0)
3232 if (*field[i] == '-')
3234 /* flip the sign on all fields */
3235 tm->tm_hour = -tm->tm_hour;
3236 tm->tm_min = -tm->tm_min;
3237 tm->tm_sec = -tm->tm_sec;
3242 * Set the next type to be a day, if units are not
3243 * specified. This handles the case of '1 +02:03' since we
3244 * are reading right to left.
3251 * Otherwise, fall through to DTK_NUMBER case, which can
3252 * handle signed float numbers and signed year-month values.
3259 if (type == IGNORE_DTF)
3261 /* use typmod to decide what rightmost field is */
3264 case INTERVAL_MASK(YEAR):
3267 case INTERVAL_MASK(MONTH):
3268 case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
3271 case INTERVAL_MASK(DAY):
3274 case INTERVAL_MASK(HOUR):
3275 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
3278 case INTERVAL_MASK(MINUTE):
3279 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
3280 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
3283 case INTERVAL_MASK(SECOND):
3284 case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
3285 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
3286 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
3296 val = strtoint(field[i], &cp, 10);
3297 if (errno == ERANGE)
3298 return DTERR_FIELD_OVERFLOW;
3302 /* SQL "years-months" syntax */
3305 val2 = strtoint(cp + 1, &cp, 10);
3306 if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3307 return DTERR_FIELD_OVERFLOW;
3309 return DTERR_BAD_FORMAT;
3311 if (*field[i] == '-')
3313 if (((double) val * MONTHS_PER_YEAR + val2) > INT_MAX ||
3314 ((double) val * MONTHS_PER_YEAR + val2) < INT_MIN)
3315 return DTERR_FIELD_OVERFLOW;
3316 val = val * MONTHS_PER_YEAR + val2;
3319 else if (*cp == '.')
3322 fval = strtod(cp, &cp);
3323 if (*cp != '\0' || errno != 0)
3324 return DTERR_BAD_FORMAT;
3326 if (*field[i] == '-')
3329 else if (*cp == '\0')
3332 return DTERR_BAD_FORMAT;
3334 tmask = 0; /* DTK_M(type); */
3339 #ifdef HAVE_INT64_TIMESTAMP
3340 *fsec += rint(val + fval);
3342 *fsec += (val + fval) * 1e-6;
3344 tmask = DTK_M(MICROSECOND);
3348 /* avoid overflowing the fsec field */
3349 tm->tm_sec += val / 1000;
3350 val -= (val / 1000) * 1000;
3351 #ifdef HAVE_INT64_TIMESTAMP
3352 *fsec += rint((val + fval) * 1000);
3354 *fsec += (val + fval) * 1e-3;
3356 tmask = DTK_M(MILLISECOND);
3361 #ifdef HAVE_INT64_TIMESTAMP
3362 *fsec += rint(fval * 1000000);
3368 * If any subseconds were specified, consider this
3369 * microsecond and millisecond input as well.
3372 tmask = DTK_M(SECOND);
3374 tmask = DTK_ALL_SECS_M;
3379 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3380 tmask = DTK_M(MINUTE);
3385 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3386 tmask = DTK_M(HOUR);
3387 type = DTK_DAY; /* set for next field */
3392 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3397 tm->tm_mday += val * 7;
3398 AdjustFractDays(fval, tm, fsec, 7);
3399 tmask = DTK_M(WEEK);
3404 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3405 tmask = DTK_M(MONTH);
3411 tm->tm_mon += fval * MONTHS_PER_YEAR;
3412 tmask = DTK_M(YEAR);
3416 tm->tm_year += val * 10;
3418 tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
3419 tmask = DTK_M(DECADE);
3423 tm->tm_year += val * 100;
3425 tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
3426 tmask = DTK_M(CENTURY);
3429 case DTK_MILLENNIUM:
3430 tm->tm_year += val * 1000;
3432 tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
3433 tmask = DTK_M(MILLENNIUM);
3437 return DTERR_BAD_FORMAT;
3443 type = DecodeUnits(i, field[i], &val);
3444 if (type == IGNORE_DTF)
3447 tmask = 0; /* DTK_M(type); */
3460 tmask = (DTK_DATE_M | DTK_TIME_M);
3465 return DTERR_BAD_FORMAT;
3470 return DTERR_BAD_FORMAT;
3474 return DTERR_BAD_FORMAT;
3478 /* ensure that at least one time field has been found */
3480 return DTERR_BAD_FORMAT;
3482 /* ensure fractional seconds are fractional */
3487 #ifdef HAVE_INT64_TIMESTAMP
3488 sec = *fsec / USECS_PER_SEC;
3489 *fsec -= sec * USECS_PER_SEC;
3491 TMODULO(*fsec, sec, 1.0);
3497 * The SQL standard defines the interval literal
3499 * to mean "negative 1 days and negative 1 hours", while Postgres
3500 * traditionally treats this as meaning "negative 1 days and positive
3501 * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3502 * to all fields if there are no other explicit signs.
3504 * We leave the signs alone if there are additional explicit signs.
3505 * This protects us against misinterpreting postgres-style dump output,
3506 * since the postgres-style output code has always put an explicit sign on
3507 * all fields following a negative field. But note that SQL-spec output
3508 * is ambiguous and can be misinterpreted on load! (So it's best practice
3509 * to dump in postgres style, not SQL style.)
3512 if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
3514 /* Check for additional explicit signs */
3515 bool more_signs = false;
3517 for (i = 1; i < nf; i++)
3519 if (*field[i] == '-' || *field[i] == '+')
3529 * Rather than re-determining which field was field[0], just force
3535 tm->tm_sec = -tm->tm_sec;
3537 tm->tm_min = -tm->tm_min;
3538 if (tm->tm_hour > 0)
3539 tm->tm_hour = -tm->tm_hour;
3540 if (tm->tm_mday > 0)
3541 tm->tm_mday = -tm->tm_mday;
3543 tm->tm_mon = -tm->tm_mon;
3544 if (tm->tm_year > 0)
3545 tm->tm_year = -tm->tm_year;
3549 /* finally, AGO negates everything */
3553 tm->tm_sec = -tm->tm_sec;
3554 tm->tm_min = -tm->tm_min;
3555 tm->tm_hour = -tm->tm_hour;
3556 tm->tm_mday = -tm->tm_mday;
3557 tm->tm_mon = -tm->tm_mon;
3558 tm->tm_year = -tm->tm_year;
3566 * Helper functions to avoid duplicated code in DecodeISO8601Interval.
3568 * Parse a decimal value and break it into integer and fractional parts.
3569 * Returns 0 or DTERR code.
3572 ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
3576 if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
3577 return DTERR_BAD_FORMAT;
3579 val = strtod(str, endptr);
3580 /* did we not see anything that looks like a double? */
3581 if (*endptr == str || errno != 0)
3582 return DTERR_BAD_FORMAT;
3583 /* watch out for overflow */
3584 if (val < INT_MIN || val > INT_MAX)
3585 return DTERR_FIELD_OVERFLOW;
3586 /* be very sure we truncate towards zero (cf dtrunc()) */
3588 *ipart = (int) floor(val);
3590 *ipart = (int) -floor(-val);
3591 *fpart = val - *ipart;
3596 * Determine number of integral digits in a valid ISO 8601 number field
3597 * (we should ignore sign and any fraction part)
3600 ISO8601IntegerWidth(char *fieldstart)
3602 /* We might have had a leading '-' */
3603 if (*fieldstart == '-')
3605 return strspn(fieldstart, "0123456789");
3609 /* DecodeISO8601Interval()
3610 * Decode an ISO 8601 time interval of the "format with designators"
3611 * (section 4.4.3.2) or "alternative format" (section 4.4.3.3)
3612 * Examples: P1D for 1 day
3614 * P2Y6M7DT1H30M for 2 years, 6 months, 7 days 1 hour 30 min
3615 * P0002-06-07T01:30:00 the same value in alternative format
3617 * Returns 0 if successful, DTERR code if bogus input detected.
3618 * Note: error code should be DTERR_BAD_FORMAT if input doesn't look like
3619 * ISO8601, otherwise this could cause unexpected error messages.
3620 * dtype, tm, fsec are output parameters.
3622 * A couple exceptions from the spec:
3623 * - a week field ('W') may coexist with other units
3624 * - allows decimals in fields other than the least significant unit.
3627 DecodeISO8601Interval(char *str,
3628 int *dtype, struct pg_tm * tm, fsec_t *fsec)
3630 bool datepart = true;
3631 bool havefield = false;
3634 ClearPgTm(tm, fsec);
3636 if (strlen(str) < 2 || str[0] != 'P')
3637 return DTERR_BAD_FORMAT;
3648 if (*str == 'T') /* T indicates the beginning of the time part */
3657 dterr = ParseISO8601Number(str, &str, &val, &fval);
3662 * Note: we could step off the end of the string here. Code below
3663 * *must* exit the loop if unit == '\0'.
3669 switch (unit) /* before T: Y M W D */
3673 tm->tm_mon += (fval * MONTHS_PER_YEAR);
3677 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3680 tm->tm_mday += val * 7;
3681 AdjustFractDays(fval, tm, fsec, 7);
3685 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3687 case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3689 if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3691 tm->tm_year += val / 10000;
3692 tm->tm_mon += (val / 100) % 100;
3693 tm->tm_mday += val % 100;
3694 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3701 /* Else fall through to extended alternative format */
3702 case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3705 return DTERR_BAD_FORMAT;
3708 tm->tm_mon += (fval * MONTHS_PER_YEAR);
3718 dterr = ParseISO8601Number(str, &str, &val, &fval);
3722 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3732 return DTERR_BAD_FORMAT;
3735 dterr = ParseISO8601Number(str, &str, &val, &fval);
3739 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3748 return DTERR_BAD_FORMAT;
3750 /* not a valid date unit suffix */
3751 return DTERR_BAD_FORMAT;
3756 switch (unit) /* after T: H M S */
3760 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3764 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3768 AdjustFractSeconds(fval, tm, fsec, 1);
3770 case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3771 if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3773 tm->tm_hour += val / 10000;
3774 tm->tm_min += (val / 100) % 100;
3775 tm->tm_sec += val % 100;
3776 AdjustFractSeconds(fval, tm, fsec, 1);
3779 /* Else fall through to extended alternative format */
3780 case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3783 return DTERR_BAD_FORMAT;
3786 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3790 dterr = ParseISO8601Number(str, &str, &val, &fval);
3794 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3798 return DTERR_BAD_FORMAT;
3801 dterr = ParseISO8601Number(str, &str, &val, &fval);
3805 AdjustFractSeconds(fval, tm, fsec, 1);
3808 return DTERR_BAD_FORMAT;
3811 /* not a valid time unit suffix */
3812 return DTERR_BAD_FORMAT;
3824 * Decode text string using lookup table.
3826 * This routine recognizes keywords associated with time interval units.
3828 * Given string must be lowercased already.
3830 * Implement a cache lookup since it is likely that dates
3831 * will be related in format.
3834 DecodeUnits(int field, char *lowtoken, int *val)
3839 tp = deltacache[field];
3840 /* use strncmp so that we match truncated tokens */
3841 if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3843 tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3847 type = UNKNOWN_FIELD;
3852 deltacache[field] = tp;
3858 } /* DecodeUnits() */
3861 * Report an error detected by one of the datetime input processing routines.
3863 * dterr is the error code, str is the original input string, datatype is
3864 * the name of the datatype we were trying to accept.
3866 * Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
3867 * DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
3868 * separate SQLSTATE codes, so ...
3871 DateTimeParseError(int dterr, const char *str, const char *datatype)
3875 case DTERR_FIELD_OVERFLOW:
3877 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3878 errmsg("date/time field value out of range: \"%s\"",
3881 case DTERR_MD_FIELD_OVERFLOW:
3882 /* <nanny>same as above, but add hint about DateStyle</nanny> */
3884 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3885 errmsg("date/time field value out of range: \"%s\"",
3887 errhint("Perhaps you need a different \"datestyle\" setting.")));
3889 case DTERR_INTERVAL_OVERFLOW:
3891 (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
3892 errmsg("interval field value out of range: \"%s\"",
3895 case DTERR_TZDISP_OVERFLOW:
3897 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
3898 errmsg("time zone displacement out of range: \"%s\"",
3901 case DTERR_BAD_FORMAT:
3904 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3905 errmsg("invalid input syntax for type %s: \"%s\"",
3912 * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
3913 * is WAY faster than the generic bsearch().
3915 static const datetkn *
3916 datebsearch(const char *key, const datetkn *base, int nel)
3920 const datetkn *last = base + nel - 1,
3924 while (last >= base)
3926 position = base + ((last - base) >> 1);
3927 /* precheck the first character for a bit of extra speed */
3928 result = (int) key[0] - (int) position->token[0];
3931 /* use strncmp so that we match truncated tokens */
3932 result = strncmp(key, position->token, TOKMAXLEN);
3937 last = position - 1;
3939 base = position + 1;
3946 * Copies representation of a numeric timezone offset to str.
3948 * Returns a pointer to the new end of string. No NUL terminator is put
3949 * there; callers are responsible for NUL terminating str themselves.
3952 EncodeTimezone(char *str, int tz, int style)
3959 min = sec / SECS_PER_MINUTE;
3960 sec -= min * SECS_PER_MINUTE;
3961 hour = min / MINS_PER_HOUR;
3962 min -= hour * MINS_PER_HOUR;
3964 /* TZ is negated compared to sign we wish to display ... */
3965 *str++ = (tz <= 0 ? '+' : '-');
3969 str = pg_ltostr_zeropad(str, hour, 2);
3971 str = pg_ltostr_zeropad(str, min, 2);
3973 str = pg_ltostr_zeropad(str, sec, 2);
3975 else if (min != 0 || style == USE_XSD_DATES)
3977 str = pg_ltostr_zeropad(str, hour, 2);
3979 str = pg_ltostr_zeropad(str, min, 2);
3982 str = pg_ltostr_zeropad(str, hour, 2);
3987 * Encode date as local time.
3990 EncodeDateOnly(struct pg_tm * tm, int style, char *str)
3992 Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
3998 /* compatible with ISO date formats */
3999 str = pg_ltostr_zeropad(str,
4000 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4002 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4004 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4008 /* compatible with Oracle/Ingres date formats */
4009 if (DateOrder == DATEORDER_DMY)
4011 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4013 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4017 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4019 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4022 str = pg_ltostr_zeropad(str,
4023 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4026 case USE_GERMAN_DATES:
4027 /* German-style date format */
4028 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4030 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4032 str = pg_ltostr_zeropad(str,
4033 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4036 case USE_POSTGRES_DATES:
4038 /* traditional date-only style for Postgres */
4039 if (DateOrder == DATEORDER_DMY)
4041 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4043 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4047 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4049 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4052 str = pg_ltostr_zeropad(str,
4053 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4057 if (tm->tm_year <= 0)
4059 memcpy(str, " BC", 3); /* Don't copy NUL */
4067 * Encode time fields only.
4069 * tm and fsec are the value to encode, print_tz determines whether to include
4070 * a time zone (the difference between time and timetz types), tz is the
4071 * numeric time zone offset, style is the date style, str is where to write the
4075 EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
4077 str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4079 str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4081 str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
4083 str = EncodeTimezone(str, tz, style);
4089 * Encode date and time interpreted as local time.
4091 * tm and fsec are the value to encode, print_tz determines whether to include
4092 * a time zone (the difference between timestamp and timestamptz types), tz is
4093 * the numeric time zone offset, tzn is the textual time zone, which if
4094 * specified will be used instead of tz by some styles, style is the date
4095 * style, str is where to write the output.
4097 * Supported date styles:
4098 * Postgres - day mon hh:mm:ss yyyy tz
4099 * SQL - mm/dd/yyyy hh:mm:ss.ss tz
4100 * ISO - yyyy-mm-dd hh:mm:ss+/-tz
4101 * German - dd.mm.yyyy hh:mm:ss tz
4102 * XSD - yyyy-mm-ddThh:mm:ss.ss+/-tz
4105 EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
4109 Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4112 * Negative tm_isdst means we have no valid time zone translation.
4114 if (tm->tm_isdst < 0)
4121 /* Compatible with ISO-8601 date formats */
4122 str = pg_ltostr_zeropad(str,
4123 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4125 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4127 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4128 *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4129 str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4131 str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4133 str = AppendTimestampSeconds(str, tm, fsec);
4135 str = EncodeTimezone(str, tz, style);
4139 /* Compatible with Oracle/Ingres date formats */
4140 if (DateOrder == DATEORDER_DMY)
4142 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4144 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4148 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4150 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4153 str = pg_ltostr_zeropad(str,
4154 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4156 str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4158 str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4160 str = AppendTimestampSeconds(str, tm, fsec);
4163 * Note: the uses of %.*s in this function would be risky if the
4164 * timezone names ever contain non-ASCII characters. However, all
4165 * TZ abbreviations in the IANA database are plain ASCII.
4171 sprintf(str, " %.*s", MAXTZLEN, tzn);
4175 str = EncodeTimezone(str, tz, style);
4179 case USE_GERMAN_DATES:
4180 /* German variant on European style */
4181 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4183 str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4185 str = pg_ltostr_zeropad(str,
4186 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4188 str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4190 str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4192 str = AppendTimestampSeconds(str, tm, fsec);
4198 sprintf(str, " %.*s", MAXTZLEN, tzn);
4202 str = EncodeTimezone(str, tz, style);
4206 case USE_POSTGRES_DATES:
4208 /* Backward-compatible with traditional Postgres abstime dates */
4209 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4210 tm->tm_wday = j2day(day);
4211 memcpy(str, days[tm->tm_wday], 3);
4214 if (DateOrder == DATEORDER_DMY)
4216 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4218 memcpy(str, months[tm->tm_mon - 1], 3);
4223 memcpy(str, months[tm->tm_mon - 1], 3);
4226 str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4229 str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4231 str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4233 str = AppendTimestampSeconds(str, tm, fsec);
4235 str = pg_ltostr_zeropad(str,
4236 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4242 sprintf(str, " %.*s", MAXTZLEN, tzn);
4248 * We have a time zone, but no string version. Use the
4249 * numeric form, but be sure to include a leading space to
4250 * avoid formatting something which would be rejected by
4251 * the date/time parser later. - thomas 2001-10-19
4254 str = EncodeTimezone(str, tz, style);
4260 if (tm->tm_year <= 0)
4262 memcpy(str, " BC", 3); /* Don't copy NUL */
4270 * Helper functions to avoid duplicated code in EncodeInterval.
4273 /* Append an ISO-8601-style interval field, but only if value isn't zero */
4275 AddISO8601IntPart(char *cp, int value, char units)
4279 sprintf(cp, "%d%c", value, units);
4280 return cp + strlen(cp);
4283 /* Append a postgres-style interval field, but only if value isn't zero */
4285 AddPostgresIntPart(char *cp, int value, const char *units,
4286 bool *is_zero, bool *is_before)
4290 sprintf(cp, "%s%s%d %s%s",
4291 (!*is_zero) ? " " : "",
4292 (*is_before && value > 0) ? "+" : "",
4295 (value != 1) ? "s" : "");
4298 * Each nonzero field sets is_before for (only) the next one. This is a
4299 * tad bizarre but it's how it worked before...
4301 *is_before = (value < 0);
4303 return cp + strlen(cp);
4306 /* Append a verbose-style interval field, but only if value isn't zero */
4308 AddVerboseIntPart(char *cp, int value, const char *units,
4309 bool *is_zero, bool *is_before)
4313 /* first nonzero value sets is_before */
4316 *is_before = (value < 0);
4319 else if (*is_before)
4321 sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
4323 return cp + strlen(cp);
4328 * Interpret time structure as a delta time and convert to string.
4330 * Support "traditional Postgres" and ISO-8601 styles.
4331 * Actually, afaik ISO does not address time interval formatting,
4332 * but this looks similar to the spec for absolute date/time.
4333 * - thomas 1998-04-30
4335 * Actually, afaik, ISO 8601 does specify formats for "time
4336 * intervals...[of the]...format with time-unit designators", which
4337 * are pretty ugly. The format looks something like
4338 * P1Y1M1DT1H1M1.12345S
4339 * but useful for exchanging data with computers instead of humans.
4342 * And ISO's SQL 2008 standard specifies standards for
4343 * "year-month literal"s (that look like '2-3') and
4344 * "day-time literal"s (that look like ('4 5:6:7')
4347 EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
4350 int year = tm->tm_year;
4351 int mon = tm->tm_mon;
4352 int mday = tm->tm_mday;
4353 int hour = tm->tm_hour;
4354 int min = tm->tm_min;
4355 int sec = tm->tm_sec;
4356 bool is_before = FALSE;
4357 bool is_zero = TRUE;
4360 * The sign of year and month are guaranteed to match, since they are
4361 * stored internally as "month". But we'll need to check for is_before and
4362 * is_zero when determining the signs of day and hour/minute/seconds
4367 /* SQL Standard interval format */
4368 case INTSTYLE_SQL_STANDARD:
4370 bool has_negative = year < 0 || mon < 0 ||
4371 mday < 0 || hour < 0 ||
4372 min < 0 || sec < 0 || fsec < 0;
4373 bool has_positive = year > 0 || mon > 0 ||
4374 mday > 0 || hour > 0 ||
4375 min > 0 || sec > 0 || fsec > 0;
4376 bool has_year_month = year != 0 || mon != 0;
4377 bool has_day_time = mday != 0 || hour != 0 ||
4378 min != 0 || sec != 0 || fsec != 0;
4379 bool has_day = mday != 0;
4380 bool sql_standard_value = !(has_negative && has_positive) &&
4381 !(has_year_month && has_day_time);
4384 * SQL Standard wants only 1 "<sign>" preceding the whole
4385 * interval ... but can't do that if mixed signs.
4387 if (has_negative && sql_standard_value)
4399 if (!has_negative && !has_positive)
4403 else if (!sql_standard_value)
4406 * For non sql-standard interval values, force outputting
4407 * the signs to avoid ambiguities with intervals with
4408 * mixed sign components.
4410 char year_sign = (year < 0 || mon < 0) ? '-' : '+';
4411 char day_sign = (mday < 0) ? '-' : '+';
4412 char sec_sign = (hour < 0 || min < 0 ||
4413 sec < 0 || fsec < 0) ? '-' : '+';
4415 sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
4416 year_sign, abs(year), abs(mon),
4417 day_sign, abs(mday),
4418 sec_sign, abs(hour), abs(min));
4420 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4423 else if (has_year_month)
4425 sprintf(cp, "%d-%d", year, mon);
4429 sprintf(cp, "%d %d:%02d:", mday, hour, min);
4431 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4436 sprintf(cp, "%d:%02d:", hour, min);
4438 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4444 /* ISO 8601 "time-intervals by duration only" */
4445 case INTSTYLE_ISO_8601:
4446 /* special-case zero to avoid printing nothing */
4447 if (year == 0 && mon == 0 && mday == 0 &&
4448 hour == 0 && min == 0 && sec == 0 && fsec == 0)
4450 sprintf(cp, "PT0S");
4454 cp = AddISO8601IntPart(cp, year, 'Y');
4455 cp = AddISO8601IntPart(cp, mon, 'M');
4456 cp = AddISO8601IntPart(cp, mday, 'D');
4457 if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
4459 cp = AddISO8601IntPart(cp, hour, 'H');
4460 cp = AddISO8601IntPart(cp, min, 'M');
4461 if (sec != 0 || fsec != 0)
4463 if (sec < 0 || fsec < 0)
4465 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4471 /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
4472 case INTSTYLE_POSTGRES:
4473 cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
4476 * Ideally we should spell out "month" like we do for "year" and
4477 * "day". However, for backward compatibility, we can't easily
4478 * fix this. bjm 2011-05-24
4480 cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
4481 cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
4482 if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
4484 bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
4486 sprintf(cp, "%s%s%02d:%02d:",
4488 (minus ? "-" : (is_before ? "+" : "")),
4489 abs(hour), abs(min));
4491 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4496 /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
4497 case INTSTYLE_POSTGRES_VERBOSE:
4501 cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
4502 cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
4503 cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
4504 cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
4505 cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
4506 if (sec != 0 || fsec != 0)
4509 if (sec < 0 || (sec == 0 && fsec < 0))
4513 else if (!is_before)
4518 cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4519 sprintf(cp, " sec%s",
4520 (abs(sec) != 1 || fsec != 0) ? "s" : "");
4523 /* identically zero? then put in a unitless zero... */
4534 * We've been burnt by stupid errors in the ordering of the datetkn tables
4535 * once too often. Arrange to check them during postmaster start.
4538 CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
4543 for (i = 0; i < nel; i++)
4545 /* check for token strings that don't fit */
4546 if (strlen(base[i].token) > TOKMAXLEN)
4548 /* %.*s is safe since all our tokens are ASCII */
4549 elog(LOG, "token too long in %s table: \"%.*s\"",
4551 TOKMAXLEN + 1, base[i].token);
4553 break; /* don't risk applying strcmp */
4555 /* check for out of order */
4557 strcmp(base[i - 1].token, base[i].token) >= 0)
4559 elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4570 CheckDateTokenTables(void)
4574 Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4575 Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4577 ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4578 ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4583 * Common code for temporal protransform functions. Types time, timetz,
4584 * timestamp and timestamptz each have a range of allowed precisions. An
4585 * unspecified precision is rigorously equivalent to the highest specifiable
4588 * Note: timestamp_scale throws an error when the typmod is out of range, but
4589 * we can't get there from a cast: our typmodin will have caught it already.
4592 TemporalTransform(int32 max_precis, Node *node)
4594 FuncExpr *expr = castNode(FuncExpr, node);
4598 Assert(list_length(expr->args) >= 2);
4600 typmod = (Node *) lsecond(expr->args);
4602 if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
4604 Node *source = (Node *) linitial(expr->args);
4605 int32 old_precis = exprTypmod(source);
4606 int32 new_precis = DatumGetInt32(((Const *) typmod)->constvalue);
4608 if (new_precis < 0 || new_precis == max_precis ||
4609 (old_precis >= 0 && new_precis >= old_precis))
4610 ret = relabel_to_typmod(source, new_precis);
4617 * This function gets called during timezone config file load or reload
4618 * to create the final array of timezone tokens. The argument array
4619 * is already sorted in name order.
4621 * The result is a TimeZoneAbbrevTable (which must be a single malloc'd chunk)
4622 * or NULL on malloc failure. No other error conditions are defined.
4624 TimeZoneAbbrevTable *
4625 ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
4627 TimeZoneAbbrevTable *tbl;
4631 /* Space for fixed fields and datetkn array */
4632 tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4633 n * sizeof(datetkn);
4634 tbl_size = MAXALIGN(tbl_size);
4635 /* Count up space for dynamic abbreviations */
4636 for (i = 0; i < n; i++)
4638 struct tzEntry *abbr = abbrevs + i;
4640 if (abbr->zone != NULL)
4644 dsize = offsetof(DynamicZoneAbbrev, zone) +
4645 strlen(abbr->zone) + 1;
4646 tbl_size += MAXALIGN(dsize);
4650 /* Alloc the result ... */
4651 tbl = malloc(tbl_size);
4655 /* ... and fill it in */
4656 tbl->tblsize = tbl_size;
4657 tbl->numabbrevs = n;
4658 /* in this loop, tbl_size reprises the space calculation above */
4659 tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4660 n * sizeof(datetkn);
4661 tbl_size = MAXALIGN(tbl_size);
4662 for (i = 0; i < n; i++)
4664 struct tzEntry *abbr = abbrevs + i;
4665 datetkn *dtoken = tbl->abbrevs + i;
4667 /* use strlcpy to truncate name if necessary */
4668 strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4669 if (abbr->zone != NULL)
4671 /* Allocate a DynamicZoneAbbrev for this abbreviation */
4672 DynamicZoneAbbrev *dtza;
4675 dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4677 strcpy(dtza->zone, abbr->zone);
4679 dtoken->type = DYNTZ;
4680 /* value is offset from table start to DynamicZoneAbbrev */
4681 dtoken->value = (int32) tbl_size;
4683 dsize = offsetof(DynamicZoneAbbrev, zone) +
4684 strlen(abbr->zone) + 1;
4685 tbl_size += MAXALIGN(dsize);
4689 dtoken->type = abbr->is_dst ? DTZ : TZ;
4690 dtoken->value = abbr->offset;
4694 /* Assert the two loops above agreed on size calculations */
4695 Assert(tbl->tblsize == tbl_size);
4697 /* Check the ordering, if testing */
4698 Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4704 * Install a TimeZoneAbbrevTable as the active table.
4706 * Caller is responsible that the passed table doesn't go away while in use.
4709 InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
4711 zoneabbrevtbl = tbl;
4712 /* reset abbrevcache, which may contain pointers into old table */
4713 memset(abbrevcache, 0, sizeof(abbrevcache));
4717 * Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
4720 FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
4722 DynamicZoneAbbrev *dtza;
4724 /* Just some sanity checks to prevent indexing off into nowhere */
4725 Assert(tp->type == DYNTZ);
4726 Assert(tp->value > 0 && tp->value < tbl->tblsize);
4728 dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4730 /* Look up the underlying zone if we haven't already */
4731 if (dtza->tz == NULL)
4733 dtza->tz = pg_tzset(dtza->zone);
4736 * Ideally we'd let the caller ereport instead of doing it here, but
4737 * then there is no way to report the bad time zone name.
4739 if (dtza->tz == NULL)
4741 (errcode(ERRCODE_CONFIG_FILE_ERROR),
4742 errmsg("time zone \"%s\" not recognized",
4744 errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4752 * This set-returning function reads all the available time zone abbreviations
4753 * and returns a set of (abbrev, utc_offset, is_dst).
4756 pg_timezone_abbrevs(PG_FUNCTION_ARGS)
4758 FuncCallContext *funcctx;
4765 char buffer[TOKMAXLEN + 1];
4770 Interval *resInterval;
4772 /* stuff done only on the first call of the function */
4773 if (SRF_IS_FIRSTCALL())
4776 MemoryContext oldcontext;
4778 /* create a function context for cross-call persistence */
4779 funcctx = SRF_FIRSTCALL_INIT();
4782 * switch to memory context appropriate for multiple function calls
4784 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4786 /* allocate memory for user context */
4787 pindex = (int *) palloc(sizeof(int));
4789 funcctx->user_fctx = (void *) pindex;
4792 * build tupdesc for result tuples. This must match this function's
4795 tupdesc = CreateTemplateTupleDesc(3, false);
4796 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev",
4798 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
4799 INTERVALOID, -1, 0);
4800 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_dst",
4803 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
4804 MemoryContextSwitchTo(oldcontext);
4807 /* stuff done on every call of the function */
4808 funcctx = SRF_PERCALL_SETUP();
4809 pindex = (int *) funcctx->user_fctx;
4811 if (zoneabbrevtbl == NULL ||
4812 *pindex >= zoneabbrevtbl->numabbrevs)
4813 SRF_RETURN_DONE(funcctx);
4815 tp = zoneabbrevtbl->abbrevs + *pindex;
4820 gmtoffset = tp->value;
4824 gmtoffset = tp->value;
4829 /* Determine the current meaning of the abbrev */
4834 tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp);
4835 now = GetCurrentTransactionStartTimestamp();
4836 gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now,
4840 is_dst = (bool) isdst;
4844 elog(ERROR, "unrecognized timezone type %d", (int) tp->type);
4845 gmtoffset = 0; /* keep compiler quiet */
4850 MemSet(nulls, 0, sizeof(nulls));
4853 * Convert name to text, using upcasing conversion that is the inverse of
4854 * what ParseDateTime() uses.
4856 strlcpy(buffer, tp->token, sizeof(buffer));
4857 for (p = (unsigned char *) buffer; *p; p++)
4858 *p = pg_toupper(*p);
4860 values[0] = CStringGetTextDatum(buffer);
4862 /* Convert offset (in seconds) to an interval */
4863 MemSet(&tm, 0, sizeof(struct pg_tm));
4864 tm.tm_sec = gmtoffset;
4865 resInterval = (Interval *) palloc(sizeof(Interval));
4866 tm2interval(&tm, 0, resInterval);
4867 values[1] = IntervalPGetDatum(resInterval);
4869 values[2] = BoolGetDatum(is_dst);
4873 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
4874 result = HeapTupleGetDatum(tuple);
4876 SRF_RETURN_NEXT(funcctx, result);
4880 * This set-returning function reads all the available full time zones
4881 * and returns a set of (name, abbrev, utc_offset, is_dst).
4884 pg_timezone_names(PG_FUNCTION_ARGS)
4886 MemoryContext oldcontext;
4887 FuncCallContext *funcctx;
4898 Interval *resInterval;
4901 /* stuff done only on the first call of the function */
4902 if (SRF_IS_FIRSTCALL())
4906 /* create a function context for cross-call persistence */
4907 funcctx = SRF_FIRSTCALL_INIT();
4910 * switch to memory context appropriate for multiple function calls
4912 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4914 /* initialize timezone scanning code */
4915 tzenum = pg_tzenumerate_start();
4916 funcctx->user_fctx = (void *) tzenum;
4919 * build tupdesc for result tuples. This must match this function's
4922 tupdesc = CreateTemplateTupleDesc(4, false);
4923 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
4925 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev",
4927 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "utc_offset",
4928 INTERVALOID, -1, 0);
4929 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_dst",
4932 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
4933 MemoryContextSwitchTo(oldcontext);
4936 /* stuff done on every call of the function */
4937 funcctx = SRF_PERCALL_SETUP();
4938 tzenum = (pg_tzenum *) funcctx->user_fctx;
4940 /* search for another zone to display */
4943 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4944 tz = pg_tzenumerate_next(tzenum);
4945 MemoryContextSwitchTo(oldcontext);
4949 pg_tzenumerate_end(tzenum);
4950 funcctx->user_fctx = NULL;
4951 SRF_RETURN_DONE(funcctx);
4954 /* Convert now() to local time in this zone */
4955 if (timestamp2tm(GetCurrentTransactionStartTimestamp(),
4956 &tzoff, &tm, &fsec, &tzn, tz) != 0)
4957 continue; /* ignore if conversion fails */
4960 * Ignore zic's rather silly "Factory" time zone. The long string
4961 * about "see zic manual page" is used in tzdata versions before
4962 * 2016g; we can drop it someday when we're pretty sure no such data
4963 * exists in the wild on platforms using --with-system-tzdata. In
4964 * 2016g and later, the time zone abbreviation "-00" is used for
4965 * "Factory" as well as some invalid cases, all of which we can
4966 * reasonably omit from the pg_timezone_names view.
4968 if (tzn && (strcmp(tzn, "-00") == 0 ||
4969 strcmp(tzn, "Local time zone must be set--see zic manual page") == 0))
4972 /* Found a displayable zone */
4976 MemSet(nulls, 0, sizeof(nulls));
4978 values[0] = CStringGetTextDatum(pg_get_timezone_name(tz));
4979 values[1] = CStringGetTextDatum(tzn ? tzn : "");
4981 MemSet(&itm, 0, sizeof(struct pg_tm));
4982 itm.tm_sec = -tzoff;
4983 resInterval = (Interval *) palloc(sizeof(Interval));
4984 tm2interval(&itm, 0, resInterval);
4985 values[2] = IntervalPGetDatum(resInterval);
4987 values[3] = BoolGetDatum(tm.tm_isdst > 0);
4989 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
4990 result = HeapTupleGetDatum(tuple);
4992 SRF_RETURN_NEXT(funcctx, result);