1 /*-------------------------------------------------------------------------
4 * implements DATE and TIME data types specified in SQL standard
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
11 * src/backend/utils/adt/date.c
13 *-------------------------------------------------------------------------
23 #include "access/xact.h"
24 #include "libpq/pqformat.h"
25 #include "miscadmin.h"
26 #include "nodes/supportnodes.h"
27 #include "parser/scansup.h"
28 #include "utils/array.h"
29 #include "utils/builtins.h"
30 #include "utils/date.h"
31 #include "utils/datetime.h"
32 #include "utils/hashutils.h"
33 #include "utils/sortsupport.h"
36 * gcc's -ffast-math switch breaks routines that expect exact results from
37 * expressions like timeval / SECS_PER_HOUR, where timeval is double.
40 #error -ffast-math is known to break this code
44 /* common code for timetypmodin and timetztypmodin */
46 anytime_typmodin(bool istz, ArrayType *ta)
51 tl = ArrayGetIntegerTypmods(ta, &n);
54 * we're not too tense about good error message here because grammar
55 * shouldn't allow wrong number of modifiers for TIME
59 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
60 errmsg("invalid type modifier")));
62 return anytime_typmod_check(istz, tl[0]);
65 /* exported so parse_expr.c can use it */
67 anytime_typmod_check(bool istz, int32 typmod)
71 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
72 errmsg("TIME(%d)%s precision must not be negative",
73 typmod, (istz ? " WITH TIME ZONE" : ""))));
74 if (typmod > MAX_TIME_PRECISION)
77 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
78 errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
79 typmod, (istz ? " WITH TIME ZONE" : ""),
80 MAX_TIME_PRECISION)));
81 typmod = MAX_TIME_PRECISION;
87 /* common code for timetypmodout and timetztypmodout */
89 anytime_typmodout(bool istz, int32 typmod)
91 const char *tz = istz ? " with time zone" : " without time zone";
94 return psprintf("(%d)%s", (int) typmod, tz);
96 return psprintf("%s", tz);
100 /*****************************************************************************
102 *****************************************************************************/
106 * Given date text string, convert to internal date format.
109 date_in(PG_FUNCTION_ARGS)
111 char *str = PG_GETARG_CSTRING(0);
120 char *field[MAXDATEFIELDS];
121 int ftype[MAXDATEFIELDS];
122 char workbuf[MAXDATELEN + 1];
124 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
125 field, ftype, MAXDATEFIELDS, &nf);
127 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
129 DateTimeParseError(dterr, str, "date");
142 PG_RETURN_DATEADT(date);
146 PG_RETURN_DATEADT(date);
149 DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
153 /* Prevent overflow in Julian-day routines */
154 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
156 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
157 errmsg("date out of range: \"%s\"", str)));
159 date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
161 /* Now check for just-out-of-range dates */
162 if (!IS_VALID_DATE(date))
164 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
165 errmsg("date out of range: \"%s\"", str)));
167 PG_RETURN_DATEADT(date);
171 * Given internal format date, convert to text string.
174 date_out(PG_FUNCTION_ARGS)
176 DateADT date = PG_GETARG_DATEADT(0);
180 char buf[MAXDATELEN + 1];
182 if (DATE_NOT_FINITE(date))
183 EncodeSpecialDate(date, buf);
186 j2date(date + POSTGRES_EPOCH_JDATE,
187 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
188 EncodeDateOnly(tm, DateStyle, buf);
191 result = pstrdup(buf);
192 PG_RETURN_CSTRING(result);
196 * date_recv - converts external binary format to date
199 date_recv(PG_FUNCTION_ARGS)
201 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
204 result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
206 /* Limit to the same range that date_in() accepts. */
207 if (DATE_NOT_FINITE(result))
209 else if (!IS_VALID_DATE(result))
211 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
212 errmsg("date out of range")));
214 PG_RETURN_DATEADT(result);
218 * date_send - converts date to binary format
221 date_send(PG_FUNCTION_ARGS)
223 DateADT date = PG_GETARG_DATEADT(0);
226 pq_begintypsend(&buf);
227 pq_sendint32(&buf, date);
228 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
232 * make_date - date constructor
235 make_date(PG_FUNCTION_ARGS)
242 tm.tm_year = PG_GETARG_INT32(0);
243 tm.tm_mon = PG_GETARG_INT32(1);
244 tm.tm_mday = PG_GETARG_INT32(2);
246 /* Handle negative years as BC */
250 tm.tm_year = -tm.tm_year;
253 dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
257 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
258 errmsg("date field value out of range: %d-%02d-%02d",
259 tm.tm_year, tm.tm_mon, tm.tm_mday)));
261 /* Prevent overflow in Julian-day routines */
262 if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
264 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
265 errmsg("date out of range: %d-%02d-%02d",
266 tm.tm_year, tm.tm_mon, tm.tm_mday)));
268 date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
270 /* Now check for just-out-of-range dates */
271 if (!IS_VALID_DATE(date))
273 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
274 errmsg("date out of range: %d-%02d-%02d",
275 tm.tm_year, tm.tm_mon, tm.tm_mday)));
277 PG_RETURN_DATEADT(date);
281 * Convert reserved date values to string.
284 EncodeSpecialDate(DateADT dt, char *str)
286 if (DATE_IS_NOBEGIN(dt))
288 else if (DATE_IS_NOEND(dt))
290 else /* shouldn't happen */
291 elog(ERROR, "invalid argument for EncodeSpecialDate");
296 * GetSQLCurrentDate -- implements CURRENT_DATE
299 GetSQLCurrentDate(void)
307 ts = GetCurrentTransactionStartTimestamp();
309 if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
311 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
312 errmsg("timestamp out of range")));
314 return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
318 * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
321 GetSQLCurrentTime(int32 typmod)
330 ts = GetCurrentTransactionStartTimestamp();
332 if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
334 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
335 errmsg("timestamp out of range")));
337 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
338 tm2timetz(tm, fsec, tz, result);
339 AdjustTimeForTypmod(&(result->time), typmod);
344 * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
347 GetSQLLocalTime(int32 typmod)
356 ts = GetCurrentTransactionStartTimestamp();
358 if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
360 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
361 errmsg("timestamp out of range")));
363 tm2time(tm, fsec, &result);
364 AdjustTimeForTypmod(&result, typmod);
370 * Comparison functions for dates
374 date_eq(PG_FUNCTION_ARGS)
376 DateADT dateVal1 = PG_GETARG_DATEADT(0);
377 DateADT dateVal2 = PG_GETARG_DATEADT(1);
379 PG_RETURN_BOOL(dateVal1 == dateVal2);
383 date_ne(PG_FUNCTION_ARGS)
385 DateADT dateVal1 = PG_GETARG_DATEADT(0);
386 DateADT dateVal2 = PG_GETARG_DATEADT(1);
388 PG_RETURN_BOOL(dateVal1 != dateVal2);
392 date_lt(PG_FUNCTION_ARGS)
394 DateADT dateVal1 = PG_GETARG_DATEADT(0);
395 DateADT dateVal2 = PG_GETARG_DATEADT(1);
397 PG_RETURN_BOOL(dateVal1 < dateVal2);
401 date_le(PG_FUNCTION_ARGS)
403 DateADT dateVal1 = PG_GETARG_DATEADT(0);
404 DateADT dateVal2 = PG_GETARG_DATEADT(1);
406 PG_RETURN_BOOL(dateVal1 <= dateVal2);
410 date_gt(PG_FUNCTION_ARGS)
412 DateADT dateVal1 = PG_GETARG_DATEADT(0);
413 DateADT dateVal2 = PG_GETARG_DATEADT(1);
415 PG_RETURN_BOOL(dateVal1 > dateVal2);
419 date_ge(PG_FUNCTION_ARGS)
421 DateADT dateVal1 = PG_GETARG_DATEADT(0);
422 DateADT dateVal2 = PG_GETARG_DATEADT(1);
424 PG_RETURN_BOOL(dateVal1 >= dateVal2);
428 date_cmp(PG_FUNCTION_ARGS)
430 DateADT dateVal1 = PG_GETARG_DATEADT(0);
431 DateADT dateVal2 = PG_GETARG_DATEADT(1);
433 if (dateVal1 < dateVal2)
435 else if (dateVal1 > dateVal2)
441 date_fastcmp(Datum x, Datum y, SortSupport ssup)
443 DateADT a = DatumGetDateADT(x);
444 DateADT b = DatumGetDateADT(y);
454 date_sortsupport(PG_FUNCTION_ARGS)
456 SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
458 ssup->comparator = date_fastcmp;
463 date_finite(PG_FUNCTION_ARGS)
465 DateADT date = PG_GETARG_DATEADT(0);
467 PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
471 date_larger(PG_FUNCTION_ARGS)
473 DateADT dateVal1 = PG_GETARG_DATEADT(0);
474 DateADT dateVal2 = PG_GETARG_DATEADT(1);
476 PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
480 date_smaller(PG_FUNCTION_ARGS)
482 DateADT dateVal1 = PG_GETARG_DATEADT(0);
483 DateADT dateVal2 = PG_GETARG_DATEADT(1);
485 PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
488 /* Compute difference between two dates in days.
491 date_mi(PG_FUNCTION_ARGS)
493 DateADT dateVal1 = PG_GETARG_DATEADT(0);
494 DateADT dateVal2 = PG_GETARG_DATEADT(1);
496 if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
498 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
499 errmsg("cannot subtract infinite dates")));
501 PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
504 /* Add a number of days to a date, giving a new date.
505 * Must handle both positive and negative numbers of days.
508 date_pli(PG_FUNCTION_ARGS)
510 DateADT dateVal = PG_GETARG_DATEADT(0);
511 int32 days = PG_GETARG_INT32(1);
514 if (DATE_NOT_FINITE(dateVal))
515 PG_RETURN_DATEADT(dateVal); /* can't change infinity */
517 result = dateVal + days;
519 /* Check for integer overflow and out-of-allowed-range */
520 if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
521 !IS_VALID_DATE(result))
523 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
524 errmsg("date out of range")));
526 PG_RETURN_DATEADT(result);
529 /* Subtract a number of days from a date, giving a new date.
532 date_mii(PG_FUNCTION_ARGS)
534 DateADT dateVal = PG_GETARG_DATEADT(0);
535 int32 days = PG_GETARG_INT32(1);
538 if (DATE_NOT_FINITE(dateVal))
539 PG_RETURN_DATEADT(dateVal); /* can't change infinity */
541 result = dateVal - days;
543 /* Check for integer overflow and out-of-allowed-range */
544 if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
545 !IS_VALID_DATE(result))
547 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
548 errmsg("date out of range")));
550 PG_RETURN_DATEADT(result);
555 * Promote date to timestamp.
557 * On overflow error is thrown if 'overflow' is NULL. Otherwise, '*overflow'
558 * is set to -1 (+1) when result value exceed lower (upper) boundary and zero
562 date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
566 if (DATE_IS_NOBEGIN(dateVal))
567 TIMESTAMP_NOBEGIN(result);
568 else if (DATE_IS_NOEND(dateVal))
569 TIMESTAMP_NOEND(result);
573 * Date's range is wider than timestamp's, so check for boundaries.
574 * Since dates have the same minimum values as timestamps, only upper
575 * boundary need be checked for overflow.
577 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
582 return (Timestamp) 0;
587 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
588 errmsg("date out of range for timestamp")));
592 /* date is days since 2000, timestamp is microseconds since same... */
593 result = dateVal * USECS_PER_DAY;
600 * Single-argument version of date2timestamp_opt_overflow().
603 date2timestamp(DateADT dateVal)
605 return date2timestamp_opt_overflow(dateVal, NULL);
609 * Promote date to timestamp with time zone.
611 * On overflow error is thrown if 'overflow' is NULL. Otherwise, '*overflow'
612 * is set to -1 (+1) when result value exceed lower (upper) boundary and zero
616 date2timestamptz_opt_overflow(DateADT dateVal, int *overflow)
623 if (DATE_IS_NOBEGIN(dateVal))
624 TIMESTAMP_NOBEGIN(result);
625 else if (DATE_IS_NOEND(dateVal))
626 TIMESTAMP_NOEND(result);
630 * Date's range is wider than timestamp's, so check for boundaries.
631 * Since dates have the same minimum values as timestamps, only upper
632 * boundary need be checked for overflow.
634 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
639 return (TimestampTz) 0;
644 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
645 errmsg("date out of range for timestamp")));
649 j2date(dateVal + POSTGRES_EPOCH_JDATE,
650 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
654 tz = DetermineTimeZoneOffset(tm, session_timezone);
656 result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
659 * Since it is possible to go beyond allowed timestamptz range because
660 * of time zone, check for allowed timestamp range after adding tz.
662 if (!IS_VALID_TIMESTAMP(result))
666 if (result < MIN_TIMESTAMP)
670 Assert(result >= END_TIMESTAMP);
673 return (TimestampTz) 0;
678 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
679 errmsg("date out of range for timestamp")));
688 * Single-argument version of date2timestamptz_opt_overflow().
691 date2timestamptz(DateADT dateVal)
693 return date2timestamptz_opt_overflow(dateVal, NULL);
697 * date2timestamp_no_overflow
699 * This is chartered to produce a double value that is numerically
700 * equivalent to the corresponding Timestamp value, if the date is in the
701 * valid range of Timestamps, but in any case not throw an overflow error.
702 * We can do this since the numerical range of double is greater than
703 * that of non-erroneous timestamps. The results are currently only
704 * used for statistical estimation purposes.
707 date2timestamp_no_overflow(DateADT dateVal)
711 if (DATE_IS_NOBEGIN(dateVal))
713 else if (DATE_IS_NOEND(dateVal))
717 /* date is days since 2000, timestamp is microseconds since same... */
718 result = dateVal * (double) USECS_PER_DAY;
726 * Crosstype comparison functions for dates
730 date_eq_timestamp(PG_FUNCTION_ARGS)
732 DateADT dateVal = PG_GETARG_DATEADT(0);
733 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
736 dt1 = date2timestamp(dateVal);
738 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
742 date_ne_timestamp(PG_FUNCTION_ARGS)
744 DateADT dateVal = PG_GETARG_DATEADT(0);
745 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
748 dt1 = date2timestamp(dateVal);
750 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
754 date_lt_timestamp(PG_FUNCTION_ARGS)
756 DateADT dateVal = PG_GETARG_DATEADT(0);
757 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
760 dt1 = date2timestamp(dateVal);
762 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
766 date_gt_timestamp(PG_FUNCTION_ARGS)
768 DateADT dateVal = PG_GETARG_DATEADT(0);
769 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
772 dt1 = date2timestamp(dateVal);
774 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
778 date_le_timestamp(PG_FUNCTION_ARGS)
780 DateADT dateVal = PG_GETARG_DATEADT(0);
781 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
784 dt1 = date2timestamp(dateVal);
786 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
790 date_ge_timestamp(PG_FUNCTION_ARGS)
792 DateADT dateVal = PG_GETARG_DATEADT(0);
793 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
796 dt1 = date2timestamp(dateVal);
798 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
802 date_cmp_timestamp(PG_FUNCTION_ARGS)
804 DateADT dateVal = PG_GETARG_DATEADT(0);
805 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
808 dt1 = date2timestamp(dateVal);
810 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
814 date_eq_timestamptz(PG_FUNCTION_ARGS)
816 DateADT dateVal = PG_GETARG_DATEADT(0);
817 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
820 dt1 = date2timestamptz(dateVal);
822 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
826 date_ne_timestamptz(PG_FUNCTION_ARGS)
828 DateADT dateVal = PG_GETARG_DATEADT(0);
829 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
832 dt1 = date2timestamptz(dateVal);
834 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
838 date_lt_timestamptz(PG_FUNCTION_ARGS)
840 DateADT dateVal = PG_GETARG_DATEADT(0);
841 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
844 dt1 = date2timestamptz(dateVal);
846 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
850 date_gt_timestamptz(PG_FUNCTION_ARGS)
852 DateADT dateVal = PG_GETARG_DATEADT(0);
853 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
856 dt1 = date2timestamptz(dateVal);
858 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
862 date_le_timestamptz(PG_FUNCTION_ARGS)
864 DateADT dateVal = PG_GETARG_DATEADT(0);
865 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
868 dt1 = date2timestamptz(dateVal);
870 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
874 date_ge_timestamptz(PG_FUNCTION_ARGS)
876 DateADT dateVal = PG_GETARG_DATEADT(0);
877 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
880 dt1 = date2timestamptz(dateVal);
882 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
886 date_cmp_timestamptz(PG_FUNCTION_ARGS)
888 DateADT dateVal = PG_GETARG_DATEADT(0);
889 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
892 dt1 = date2timestamptz(dateVal);
894 PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
898 timestamp_eq_date(PG_FUNCTION_ARGS)
900 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
901 DateADT dateVal = PG_GETARG_DATEADT(1);
904 dt2 = date2timestamp(dateVal);
906 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
910 timestamp_ne_date(PG_FUNCTION_ARGS)
912 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
913 DateADT dateVal = PG_GETARG_DATEADT(1);
916 dt2 = date2timestamp(dateVal);
918 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
922 timestamp_lt_date(PG_FUNCTION_ARGS)
924 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
925 DateADT dateVal = PG_GETARG_DATEADT(1);
928 dt2 = date2timestamp(dateVal);
930 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
934 timestamp_gt_date(PG_FUNCTION_ARGS)
936 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
937 DateADT dateVal = PG_GETARG_DATEADT(1);
940 dt2 = date2timestamp(dateVal);
942 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
946 timestamp_le_date(PG_FUNCTION_ARGS)
948 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
949 DateADT dateVal = PG_GETARG_DATEADT(1);
952 dt2 = date2timestamp(dateVal);
954 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
958 timestamp_ge_date(PG_FUNCTION_ARGS)
960 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
961 DateADT dateVal = PG_GETARG_DATEADT(1);
964 dt2 = date2timestamp(dateVal);
966 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
970 timestamp_cmp_date(PG_FUNCTION_ARGS)
972 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
973 DateADT dateVal = PG_GETARG_DATEADT(1);
976 dt2 = date2timestamp(dateVal);
978 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
982 timestamptz_eq_date(PG_FUNCTION_ARGS)
984 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
985 DateADT dateVal = PG_GETARG_DATEADT(1);
988 dt2 = date2timestamptz(dateVal);
990 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
994 timestamptz_ne_date(PG_FUNCTION_ARGS)
996 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
997 DateADT dateVal = PG_GETARG_DATEADT(1);
1000 dt2 = date2timestamptz(dateVal);
1002 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
1006 timestamptz_lt_date(PG_FUNCTION_ARGS)
1008 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1009 DateADT dateVal = PG_GETARG_DATEADT(1);
1012 dt2 = date2timestamptz(dateVal);
1014 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
1018 timestamptz_gt_date(PG_FUNCTION_ARGS)
1020 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1021 DateADT dateVal = PG_GETARG_DATEADT(1);
1024 dt2 = date2timestamptz(dateVal);
1026 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
1030 timestamptz_le_date(PG_FUNCTION_ARGS)
1032 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1033 DateADT dateVal = PG_GETARG_DATEADT(1);
1036 dt2 = date2timestamptz(dateVal);
1038 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
1042 timestamptz_ge_date(PG_FUNCTION_ARGS)
1044 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1045 DateADT dateVal = PG_GETARG_DATEADT(1);
1048 dt2 = date2timestamptz(dateVal);
1050 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
1054 timestamptz_cmp_date(PG_FUNCTION_ARGS)
1056 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1057 DateADT dateVal = PG_GETARG_DATEADT(1);
1060 dt2 = date2timestamptz(dateVal);
1062 PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
1066 * in_range support function for date.
1068 * We implement this by promoting the dates to timestamp (without time zone)
1069 * and then using the timestamp-and-interval in_range function.
1072 in_range_date_interval(PG_FUNCTION_ARGS)
1074 DateADT val = PG_GETARG_DATEADT(0);
1075 DateADT base = PG_GETARG_DATEADT(1);
1076 Interval *offset = PG_GETARG_INTERVAL_P(2);
1077 bool sub = PG_GETARG_BOOL(3);
1078 bool less = PG_GETARG_BOOL(4);
1080 Timestamp baseStamp;
1082 valStamp = date2timestamp(val);
1083 baseStamp = date2timestamp(base);
1085 return DirectFunctionCall5(in_range_timestamp_interval,
1086 TimestampGetDatum(valStamp),
1087 TimestampGetDatum(baseStamp),
1088 IntervalPGetDatum(offset),
1090 BoolGetDatum(less));
1094 /* Add an interval to a date, giving a new date.
1095 * Must handle both positive and negative intervals.
1097 * We implement this by promoting the date to timestamp (without time zone)
1098 * and then using the timestamp plus interval function.
1101 date_pl_interval(PG_FUNCTION_ARGS)
1103 DateADT dateVal = PG_GETARG_DATEADT(0);
1104 Interval *span = PG_GETARG_INTERVAL_P(1);
1105 Timestamp dateStamp;
1107 dateStamp = date2timestamp(dateVal);
1109 return DirectFunctionCall2(timestamp_pl_interval,
1110 TimestampGetDatum(dateStamp),
1111 PointerGetDatum(span));
1114 /* Subtract an interval from a date, giving a new date.
1115 * Must handle both positive and negative intervals.
1117 * We implement this by promoting the date to timestamp (without time zone)
1118 * and then using the timestamp minus interval function.
1121 date_mi_interval(PG_FUNCTION_ARGS)
1123 DateADT dateVal = PG_GETARG_DATEADT(0);
1124 Interval *span = PG_GETARG_INTERVAL_P(1);
1125 Timestamp dateStamp;
1127 dateStamp = date2timestamp(dateVal);
1129 return DirectFunctionCall2(timestamp_mi_interval,
1130 TimestampGetDatum(dateStamp),
1131 PointerGetDatum(span));
1135 * Convert date to timestamp data type.
1138 date_timestamp(PG_FUNCTION_ARGS)
1140 DateADT dateVal = PG_GETARG_DATEADT(0);
1143 result = date2timestamp(dateVal);
1145 PG_RETURN_TIMESTAMP(result);
1149 * Convert timestamp to date data type.
1152 timestamp_date(PG_FUNCTION_ARGS)
1154 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1160 if (TIMESTAMP_IS_NOBEGIN(timestamp))
1161 DATE_NOBEGIN(result);
1162 else if (TIMESTAMP_IS_NOEND(timestamp))
1166 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1168 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1169 errmsg("timestamp out of range")));
1171 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1174 PG_RETURN_DATEADT(result);
1178 /* date_timestamptz()
1179 * Convert date to timestamp with time zone data type.
1182 date_timestamptz(PG_FUNCTION_ARGS)
1184 DateADT dateVal = PG_GETARG_DATEADT(0);
1187 result = date2timestamptz(dateVal);
1189 PG_RETURN_TIMESTAMP(result);
1193 /* timestamptz_date()
1194 * Convert timestamp with time zone to date data type.
1197 timestamptz_date(PG_FUNCTION_ARGS)
1199 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1206 if (TIMESTAMP_IS_NOBEGIN(timestamp))
1207 DATE_NOBEGIN(result);
1208 else if (TIMESTAMP_IS_NOEND(timestamp))
1212 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1214 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1215 errmsg("timestamp out of range")));
1217 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1220 PG_RETURN_DATEADT(result);
1224 /*****************************************************************************
1226 *****************************************************************************/
1229 time_in(PG_FUNCTION_ARGS)
1231 char *str = PG_GETARG_CSTRING(0);
1234 Oid typelem = PG_GETARG_OID(1);
1236 int32 typmod = PG_GETARG_INT32(2);
1244 char workbuf[MAXDATELEN + 1];
1245 char *field[MAXDATEFIELDS];
1247 int ftype[MAXDATEFIELDS];
1249 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1250 field, ftype, MAXDATEFIELDS, &nf);
1252 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
1254 DateTimeParseError(dterr, str, "time");
1256 tm2time(tm, fsec, &result);
1257 AdjustTimeForTypmod(&result, typmod);
1259 PG_RETURN_TIMEADT(result);
1263 * Convert a tm structure to a time data type.
1266 tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
1268 *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
1269 * USECS_PER_SEC) + fsec;
1274 * Convert time data type to POSIX time structure.
1276 * For dates within the range of pg_time_t, convert to the local time zone.
1277 * If out of this range, leave as UTC (in practice that could only happen
1278 * if pg_time_t is just 32 bits) - thomas 97/05/27
1281 time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
1283 tm->tm_hour = time / USECS_PER_HOUR;
1284 time -= tm->tm_hour * USECS_PER_HOUR;
1285 tm->tm_min = time / USECS_PER_MINUTE;
1286 time -= tm->tm_min * USECS_PER_MINUTE;
1287 tm->tm_sec = time / USECS_PER_SEC;
1288 time -= tm->tm_sec * USECS_PER_SEC;
1294 time_out(PG_FUNCTION_ARGS)
1296 TimeADT time = PG_GETARG_TIMEADT(0);
1301 char buf[MAXDATELEN + 1];
1303 time2tm(time, tm, &fsec);
1304 EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
1306 result = pstrdup(buf);
1307 PG_RETURN_CSTRING(result);
1311 * time_recv - converts external binary format to time
1314 time_recv(PG_FUNCTION_ARGS)
1316 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1319 Oid typelem = PG_GETARG_OID(1);
1321 int32 typmod = PG_GETARG_INT32(2);
1324 result = pq_getmsgint64(buf);
1326 if (result < INT64CONST(0) || result > USECS_PER_DAY)
1328 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1329 errmsg("time out of range")));
1331 AdjustTimeForTypmod(&result, typmod);
1333 PG_RETURN_TIMEADT(result);
1337 * time_send - converts time to binary format
1340 time_send(PG_FUNCTION_ARGS)
1342 TimeADT time = PG_GETARG_TIMEADT(0);
1345 pq_begintypsend(&buf);
1346 pq_sendint64(&buf, time);
1347 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1351 timetypmodin(PG_FUNCTION_ARGS)
1353 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1355 PG_RETURN_INT32(anytime_typmodin(false, ta));
1359 timetypmodout(PG_FUNCTION_ARGS)
1361 int32 typmod = PG_GETARG_INT32(0);
1363 PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1367 * make_time - time constructor
1370 make_time(PG_FUNCTION_ARGS)
1372 int tm_hour = PG_GETARG_INT32(0);
1373 int tm_min = PG_GETARG_INT32(1);
1374 double sec = PG_GETARG_FLOAT8(2);
1377 /* This should match the checks in DecodeTimeOnly */
1378 if (tm_hour < 0 || tm_min < 0 || tm_min > MINS_PER_HOUR - 1 ||
1379 sec < 0 || sec > SECS_PER_MINUTE ||
1380 tm_hour > HOURS_PER_DAY ||
1381 /* test for > 24:00:00 */
1382 (tm_hour == HOURS_PER_DAY && (tm_min > 0 || sec > 0)))
1384 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
1385 errmsg("time field value out of range: %d:%02d:%02g",
1386 tm_hour, tm_min, sec)));
1388 /* This should match tm2time */
1389 time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
1390 * USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
1392 PG_RETURN_TIMEADT(time);
1398 * Planner support function for the time_scale() and timetz_scale()
1399 * length coercion functions (we need not distinguish them here).
1402 time_support(PG_FUNCTION_ARGS)
1404 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1407 if (IsA(rawreq, SupportRequestSimplify))
1409 SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1411 ret = TemporalSimplify(MAX_TIME_PRECISION, (Node *) req->fcall);
1414 PG_RETURN_POINTER(ret);
1418 * Adjust time type for specified scale factor.
1419 * Used by PostgreSQL type system to stuff columns.
1422 time_scale(PG_FUNCTION_ARGS)
1424 TimeADT time = PG_GETARG_TIMEADT(0);
1425 int32 typmod = PG_GETARG_INT32(1);
1429 AdjustTimeForTypmod(&result, typmod);
1431 PG_RETURN_TIMEADT(result);
1434 /* AdjustTimeForTypmod()
1435 * Force the precision of the time value to a specified value.
1436 * Uses *exactly* the same code as in AdjustTimestampForTypmod()
1437 * but we make a separate copy because those types do not
1438 * have a fundamental tie together but rather a coincidence of
1439 * implementation. - thomas
1442 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1444 static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1445 INT64CONST(1000000),
1454 static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1464 if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1466 if (*time >= INT64CONST(0))
1467 *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
1470 *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
1471 TimeScales[typmod]);
1477 time_eq(PG_FUNCTION_ARGS)
1479 TimeADT time1 = PG_GETARG_TIMEADT(0);
1480 TimeADT time2 = PG_GETARG_TIMEADT(1);
1482 PG_RETURN_BOOL(time1 == time2);
1486 time_ne(PG_FUNCTION_ARGS)
1488 TimeADT time1 = PG_GETARG_TIMEADT(0);
1489 TimeADT time2 = PG_GETARG_TIMEADT(1);
1491 PG_RETURN_BOOL(time1 != time2);
1495 time_lt(PG_FUNCTION_ARGS)
1497 TimeADT time1 = PG_GETARG_TIMEADT(0);
1498 TimeADT time2 = PG_GETARG_TIMEADT(1);
1500 PG_RETURN_BOOL(time1 < time2);
1504 time_le(PG_FUNCTION_ARGS)
1506 TimeADT time1 = PG_GETARG_TIMEADT(0);
1507 TimeADT time2 = PG_GETARG_TIMEADT(1);
1509 PG_RETURN_BOOL(time1 <= time2);
1513 time_gt(PG_FUNCTION_ARGS)
1515 TimeADT time1 = PG_GETARG_TIMEADT(0);
1516 TimeADT time2 = PG_GETARG_TIMEADT(1);
1518 PG_RETURN_BOOL(time1 > time2);
1522 time_ge(PG_FUNCTION_ARGS)
1524 TimeADT time1 = PG_GETARG_TIMEADT(0);
1525 TimeADT time2 = PG_GETARG_TIMEADT(1);
1527 PG_RETURN_BOOL(time1 >= time2);
1531 time_cmp(PG_FUNCTION_ARGS)
1533 TimeADT time1 = PG_GETARG_TIMEADT(0);
1534 TimeADT time2 = PG_GETARG_TIMEADT(1);
1537 PG_RETURN_INT32(-1);
1544 time_hash(PG_FUNCTION_ARGS)
1546 return hashint8(fcinfo);
1550 time_hash_extended(PG_FUNCTION_ARGS)
1552 return hashint8extended(fcinfo);
1556 time_larger(PG_FUNCTION_ARGS)
1558 TimeADT time1 = PG_GETARG_TIMEADT(0);
1559 TimeADT time2 = PG_GETARG_TIMEADT(1);
1561 PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1565 time_smaller(PG_FUNCTION_ARGS)
1567 TimeADT time1 = PG_GETARG_TIMEADT(0);
1568 TimeADT time2 = PG_GETARG_TIMEADT(1);
1570 PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1573 /* overlaps_time() --- implements the SQL OVERLAPS operator.
1575 * Algorithm is per SQL spec. This is much harder than you'd think
1576 * because the spec requires us to deliver a non-null answer in some cases
1577 * where some of the inputs are null.
1580 overlaps_time(PG_FUNCTION_ARGS)
1583 * The arguments are TimeADT, but we leave them as generic Datums to avoid
1584 * dereferencing nulls (TimeADT is pass-by-reference!)
1586 Datum ts1 = PG_GETARG_DATUM(0);
1587 Datum te1 = PG_GETARG_DATUM(1);
1588 Datum ts2 = PG_GETARG_DATUM(2);
1589 Datum te2 = PG_GETARG_DATUM(3);
1590 bool ts1IsNull = PG_ARGISNULL(0);
1591 bool te1IsNull = PG_ARGISNULL(1);
1592 bool ts2IsNull = PG_ARGISNULL(2);
1593 bool te2IsNull = PG_ARGISNULL(3);
1595 #define TIMEADT_GT(t1,t2) \
1596 (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1597 #define TIMEADT_LT(t1,t2) \
1598 (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1601 * If both endpoints of interval 1 are null, the result is null (unknown).
1602 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1603 * take ts1 as the lesser endpoint.
1609 /* swap null for non-null */
1613 else if (!te1IsNull)
1615 if (TIMEADT_GT(ts1, te1))
1624 /* Likewise for interval 2. */
1629 /* swap null for non-null */
1633 else if (!te2IsNull)
1635 if (TIMEADT_GT(ts2, te2))
1645 * At this point neither ts1 nor ts2 is null, so we can consider three
1646 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1648 if (TIMEADT_GT(ts1, ts2))
1651 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1652 * in the presence of nulls it's not quite completely so.
1656 if (TIMEADT_LT(ts1, te2))
1657 PG_RETURN_BOOL(true);
1662 * If te1 is not null then we had ts1 <= te1 above, and we just found
1663 * ts1 >= te2, hence te1 >= te2.
1665 PG_RETURN_BOOL(false);
1667 else if (TIMEADT_LT(ts1, ts2))
1669 /* This case is ts2 < te1 OR te2 < te1 */
1672 if (TIMEADT_LT(ts2, te1))
1673 PG_RETURN_BOOL(true);
1678 * If te2 is not null then we had ts2 <= te2 above, and we just found
1679 * ts2 >= te1, hence te2 >= te1.
1681 PG_RETURN_BOOL(false);
1686 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1687 * rather silly way of saying "true if both are nonnull, else null".
1689 if (te1IsNull || te2IsNull)
1691 PG_RETURN_BOOL(true);
1699 * Convert timestamp to time data type.
1702 timestamp_time(PG_FUNCTION_ARGS)
1704 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1710 if (TIMESTAMP_NOT_FINITE(timestamp))
1713 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1715 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1716 errmsg("timestamp out of range")));
1719 * Could also do this with time = (timestamp / USECS_PER_DAY *
1720 * USECS_PER_DAY) - timestamp;
1722 result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1723 USECS_PER_SEC) + fsec;
1725 PG_RETURN_TIMEADT(result);
1728 /* timestamptz_time()
1729 * Convert timestamptz to time data type.
1732 timestamptz_time(PG_FUNCTION_ARGS)
1734 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1741 if (TIMESTAMP_NOT_FINITE(timestamp))
1744 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1746 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1747 errmsg("timestamp out of range")));
1750 * Could also do this with time = (timestamp / USECS_PER_DAY *
1751 * USECS_PER_DAY) - timestamp;
1753 result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1754 USECS_PER_SEC) + fsec;
1756 PG_RETURN_TIMEADT(result);
1759 /* datetime_timestamp()
1760 * Convert date and time to timestamp data type.
1763 datetime_timestamp(PG_FUNCTION_ARGS)
1765 DateADT date = PG_GETARG_DATEADT(0);
1766 TimeADT time = PG_GETARG_TIMEADT(1);
1769 result = date2timestamp(date);
1770 if (!TIMESTAMP_NOT_FINITE(result))
1773 if (!IS_VALID_TIMESTAMP(result))
1775 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1776 errmsg("timestamp out of range")));
1779 PG_RETURN_TIMESTAMP(result);
1783 * Convert time to interval data type.
1786 time_interval(PG_FUNCTION_ARGS)
1788 TimeADT time = PG_GETARG_TIMEADT(0);
1791 result = (Interval *) palloc(sizeof(Interval));
1793 result->time = time;
1797 PG_RETURN_INTERVAL_P(result);
1801 * Convert interval to time data type.
1803 * This is defined as producing the fractional-day portion of the interval.
1804 * Therefore, we can just ignore the months field. It is not real clear
1805 * what to do with negative intervals, but we choose to subtract the floor,
1806 * so that, say, '-2 hours' becomes '22:00:00'.
1809 interval_time(PG_FUNCTION_ARGS)
1811 Interval *span = PG_GETARG_INTERVAL_P(0);
1815 result = span->time;
1816 if (result >= USECS_PER_DAY)
1818 days = result / USECS_PER_DAY;
1819 result -= days * USECS_PER_DAY;
1821 else if (result < 0)
1823 days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
1824 result += days * USECS_PER_DAY;
1827 PG_RETURN_TIMEADT(result);
1831 * Subtract two times to produce an interval.
1834 time_mi_time(PG_FUNCTION_ARGS)
1836 TimeADT time1 = PG_GETARG_TIMEADT(0);
1837 TimeADT time2 = PG_GETARG_TIMEADT(1);
1840 result = (Interval *) palloc(sizeof(Interval));
1844 result->time = time1 - time2;
1846 PG_RETURN_INTERVAL_P(result);
1849 /* time_pl_interval()
1850 * Add interval to time.
1853 time_pl_interval(PG_FUNCTION_ARGS)
1855 TimeADT time = PG_GETARG_TIMEADT(0);
1856 Interval *span = PG_GETARG_INTERVAL_P(1);
1859 result = time + span->time;
1860 result -= result / USECS_PER_DAY * USECS_PER_DAY;
1861 if (result < INT64CONST(0))
1862 result += USECS_PER_DAY;
1864 PG_RETURN_TIMEADT(result);
1867 /* time_mi_interval()
1868 * Subtract interval from time.
1871 time_mi_interval(PG_FUNCTION_ARGS)
1873 TimeADT time = PG_GETARG_TIMEADT(0);
1874 Interval *span = PG_GETARG_INTERVAL_P(1);
1877 result = time - span->time;
1878 result -= result / USECS_PER_DAY * USECS_PER_DAY;
1879 if (result < INT64CONST(0))
1880 result += USECS_PER_DAY;
1882 PG_RETURN_TIMEADT(result);
1886 * in_range support function for time.
1889 in_range_time_interval(PG_FUNCTION_ARGS)
1891 TimeADT val = PG_GETARG_TIMEADT(0);
1892 TimeADT base = PG_GETARG_TIMEADT(1);
1893 Interval *offset = PG_GETARG_INTERVAL_P(2);
1894 bool sub = PG_GETARG_BOOL(3);
1895 bool less = PG_GETARG_BOOL(4);
1899 * Like time_pl_interval/time_mi_interval, we disregard the month and day
1900 * fields of the offset. So our test for negative should too.
1902 if (offset->time < 0)
1904 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
1905 errmsg("invalid preceding or following size in window function")));
1908 * We can't use time_pl_interval/time_mi_interval here, because their
1909 * wraparound behavior would give wrong (or at least undesirable) answers.
1910 * Fortunately the equivalent non-wrapping behavior is trivial, especially
1911 * since we don't worry about integer overflow.
1914 sum = base - offset->time;
1916 sum = base + offset->time;
1919 PG_RETURN_BOOL(val <= sum);
1921 PG_RETURN_BOOL(val >= sum);
1926 * Extract specified field from time type.
1929 time_part(PG_FUNCTION_ARGS)
1931 text *units = PG_GETARG_TEXT_PP(0);
1932 TimeADT time = PG_GETARG_TIMEADT(1);
1938 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1939 VARSIZE_ANY_EXHDR(units),
1942 type = DecodeUnits(0, lowunits, &val);
1943 if (type == UNKNOWN_FIELD)
1944 type = DecodeSpecial(0, lowunits, &val);
1952 time2tm(time, tm, &fsec);
1957 result = tm->tm_sec * 1000000.0 + fsec;
1961 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
1965 result = tm->tm_sec + fsec / 1000000.0;
1969 result = tm->tm_min;
1973 result = tm->tm_hour;
1985 case DTK_MILLENNIUM:
1989 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1990 errmsg("\"time\" units \"%s\" not recognized",
1995 else if (type == RESERV && val == DTK_EPOCH)
1997 result = time / 1000000.0;
2002 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2003 errmsg("\"time\" units \"%s\" not recognized",
2008 PG_RETURN_FLOAT8(result);
2012 /*****************************************************************************
2013 * Time With Time Zone ADT
2014 *****************************************************************************/
2017 * Convert a tm structure to a time data type.
2020 tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
2022 result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
2023 USECS_PER_SEC) + fsec;
2030 timetz_in(PG_FUNCTION_ARGS)
2032 char *str = PG_GETARG_CSTRING(0);
2035 Oid typelem = PG_GETARG_OID(1);
2037 int32 typmod = PG_GETARG_INT32(2);
2045 char workbuf[MAXDATELEN + 1];
2046 char *field[MAXDATEFIELDS];
2048 int ftype[MAXDATEFIELDS];
2050 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
2051 field, ftype, MAXDATEFIELDS, &nf);
2053 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
2055 DateTimeParseError(dterr, str, "time with time zone");
2057 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2058 tm2timetz(tm, fsec, tz, result);
2059 AdjustTimeForTypmod(&(result->time), typmod);
2061 PG_RETURN_TIMETZADT_P(result);
2065 timetz_out(PG_FUNCTION_ARGS)
2067 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2073 char buf[MAXDATELEN + 1];
2075 timetz2tm(time, tm, &fsec, &tz);
2076 EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
2078 result = pstrdup(buf);
2079 PG_RETURN_CSTRING(result);
2083 * timetz_recv - converts external binary format to timetz
2086 timetz_recv(PG_FUNCTION_ARGS)
2088 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
2091 Oid typelem = PG_GETARG_OID(1);
2093 int32 typmod = PG_GETARG_INT32(2);
2096 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2098 result->time = pq_getmsgint64(buf);
2100 if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
2102 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2103 errmsg("time out of range")));
2105 result->zone = pq_getmsgint(buf, sizeof(result->zone));
2107 /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
2108 if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
2110 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
2111 errmsg("time zone displacement out of range")));
2113 AdjustTimeForTypmod(&(result->time), typmod);
2115 PG_RETURN_TIMETZADT_P(result);
2119 * timetz_send - converts timetz to binary format
2122 timetz_send(PG_FUNCTION_ARGS)
2124 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2127 pq_begintypsend(&buf);
2128 pq_sendint64(&buf, time->time);
2129 pq_sendint32(&buf, time->zone);
2130 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2134 timetztypmodin(PG_FUNCTION_ARGS)
2136 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
2138 PG_RETURN_INT32(anytime_typmodin(true, ta));
2142 timetztypmodout(PG_FUNCTION_ARGS)
2144 int32 typmod = PG_GETARG_INT32(0);
2146 PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
2151 * Convert TIME WITH TIME ZONE data type to POSIX time structure.
2154 timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
2156 TimeOffset trem = time->time;
2158 tm->tm_hour = trem / USECS_PER_HOUR;
2159 trem -= tm->tm_hour * USECS_PER_HOUR;
2160 tm->tm_min = trem / USECS_PER_MINUTE;
2161 trem -= tm->tm_min * USECS_PER_MINUTE;
2162 tm->tm_sec = trem / USECS_PER_SEC;
2163 *fsec = trem - tm->tm_sec * USECS_PER_SEC;
2172 * Adjust time type for specified scale factor.
2173 * Used by PostgreSQL type system to stuff columns.
2176 timetz_scale(PG_FUNCTION_ARGS)
2178 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2179 int32 typmod = PG_GETARG_INT32(1);
2182 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2184 result->time = time->time;
2185 result->zone = time->zone;
2187 AdjustTimeForTypmod(&(result->time), typmod);
2189 PG_RETURN_TIMETZADT_P(result);
2194 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
2199 /* Primary sort is by true (GMT-equivalent) time */
2200 t1 = time1->time + (time1->zone * USECS_PER_SEC);
2201 t2 = time2->time + (time2->zone * USECS_PER_SEC);
2209 * If same GMT time, sort by timezone; we only want to say that two
2210 * timetz's are equal if both the time and zone parts are equal.
2212 if (time1->zone > time2->zone)
2214 if (time1->zone < time2->zone)
2221 timetz_eq(PG_FUNCTION_ARGS)
2223 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2224 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2226 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2230 timetz_ne(PG_FUNCTION_ARGS)
2232 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2233 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2235 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2239 timetz_lt(PG_FUNCTION_ARGS)
2241 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2242 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2244 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2248 timetz_le(PG_FUNCTION_ARGS)
2250 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2251 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2253 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2257 timetz_gt(PG_FUNCTION_ARGS)
2259 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2260 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2262 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2266 timetz_ge(PG_FUNCTION_ARGS)
2268 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2269 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2271 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2275 timetz_cmp(PG_FUNCTION_ARGS)
2277 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2278 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2280 PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2284 timetz_hash(PG_FUNCTION_ARGS)
2286 TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
2290 * To avoid any problems with padding bytes in the struct, we figure the
2291 * field hashes separately and XOR them.
2293 thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2294 Int64GetDatumFast(key->time)));
2295 thash ^= DatumGetUInt32(hash_uint32(key->zone));
2296 PG_RETURN_UINT32(thash);
2300 timetz_hash_extended(PG_FUNCTION_ARGS)
2302 TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
2303 Datum seed = PG_GETARG_DATUM(1);
2306 /* Same approach as timetz_hash */
2307 thash = DatumGetUInt64(DirectFunctionCall2(hashint8extended,
2308 Int64GetDatumFast(key->time),
2310 thash ^= DatumGetUInt64(hash_uint32_extended(key->zone,
2311 DatumGetInt64(seed)));
2312 PG_RETURN_UINT64(thash);
2316 timetz_larger(PG_FUNCTION_ARGS)
2318 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2319 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2322 if (timetz_cmp_internal(time1, time2) > 0)
2326 PG_RETURN_TIMETZADT_P(result);
2330 timetz_smaller(PG_FUNCTION_ARGS)
2332 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2333 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2336 if (timetz_cmp_internal(time1, time2) < 0)
2340 PG_RETURN_TIMETZADT_P(result);
2343 /* timetz_pl_interval()
2344 * Add interval to timetz.
2347 timetz_pl_interval(PG_FUNCTION_ARGS)
2349 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2350 Interval *span = PG_GETARG_INTERVAL_P(1);
2353 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2355 result->time = time->time + span->time;
2356 result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2357 if (result->time < INT64CONST(0))
2358 result->time += USECS_PER_DAY;
2360 result->zone = time->zone;
2362 PG_RETURN_TIMETZADT_P(result);
2365 /* timetz_mi_interval()
2366 * Subtract interval from timetz.
2369 timetz_mi_interval(PG_FUNCTION_ARGS)
2371 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2372 Interval *span = PG_GETARG_INTERVAL_P(1);
2375 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2377 result->time = time->time - span->time;
2378 result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2379 if (result->time < INT64CONST(0))
2380 result->time += USECS_PER_DAY;
2382 result->zone = time->zone;
2384 PG_RETURN_TIMETZADT_P(result);
2388 * in_range support function for timetz.
2391 in_range_timetz_interval(PG_FUNCTION_ARGS)
2393 TimeTzADT *val = PG_GETARG_TIMETZADT_P(0);
2394 TimeTzADT *base = PG_GETARG_TIMETZADT_P(1);
2395 Interval *offset = PG_GETARG_INTERVAL_P(2);
2396 bool sub = PG_GETARG_BOOL(3);
2397 bool less = PG_GETARG_BOOL(4);
2401 * Like timetz_pl_interval/timetz_mi_interval, we disregard the month and
2402 * day fields of the offset. So our test for negative should too.
2404 if (offset->time < 0)
2406 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2407 errmsg("invalid preceding or following size in window function")));
2410 * We can't use timetz_pl_interval/timetz_mi_interval here, because their
2411 * wraparound behavior would give wrong (or at least undesirable) answers.
2412 * Fortunately the equivalent non-wrapping behavior is trivial, especially
2413 * since we don't worry about integer overflow.
2416 sum.time = base->time - offset->time;
2418 sum.time = base->time + offset->time;
2419 sum.zone = base->zone;
2422 PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) <= 0);
2424 PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) >= 0);
2427 /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
2429 * Algorithm is per SQL spec. This is much harder than you'd think
2430 * because the spec requires us to deliver a non-null answer in some cases
2431 * where some of the inputs are null.
2434 overlaps_timetz(PG_FUNCTION_ARGS)
2437 * The arguments are TimeTzADT *, but we leave them as generic Datums for
2438 * convenience of notation --- and to avoid dereferencing nulls.
2440 Datum ts1 = PG_GETARG_DATUM(0);
2441 Datum te1 = PG_GETARG_DATUM(1);
2442 Datum ts2 = PG_GETARG_DATUM(2);
2443 Datum te2 = PG_GETARG_DATUM(3);
2444 bool ts1IsNull = PG_ARGISNULL(0);
2445 bool te1IsNull = PG_ARGISNULL(1);
2446 bool ts2IsNull = PG_ARGISNULL(2);
2447 bool te2IsNull = PG_ARGISNULL(3);
2449 #define TIMETZ_GT(t1,t2) \
2450 DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2451 #define TIMETZ_LT(t1,t2) \
2452 DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2455 * If both endpoints of interval 1 are null, the result is null (unknown).
2456 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2457 * take ts1 as the lesser endpoint.
2463 /* swap null for non-null */
2467 else if (!te1IsNull)
2469 if (TIMETZ_GT(ts1, te1))
2478 /* Likewise for interval 2. */
2483 /* swap null for non-null */
2487 else if (!te2IsNull)
2489 if (TIMETZ_GT(ts2, te2))
2499 * At this point neither ts1 nor ts2 is null, so we can consider three
2500 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2502 if (TIMETZ_GT(ts1, ts2))
2505 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2506 * in the presence of nulls it's not quite completely so.
2510 if (TIMETZ_LT(ts1, te2))
2511 PG_RETURN_BOOL(true);
2516 * If te1 is not null then we had ts1 <= te1 above, and we just found
2517 * ts1 >= te2, hence te1 >= te2.
2519 PG_RETURN_BOOL(false);
2521 else if (TIMETZ_LT(ts1, ts2))
2523 /* This case is ts2 < te1 OR te2 < te1 */
2526 if (TIMETZ_LT(ts2, te1))
2527 PG_RETURN_BOOL(true);
2532 * If te2 is not null then we had ts2 <= te2 above, and we just found
2533 * ts2 >= te1, hence te2 >= te1.
2535 PG_RETURN_BOOL(false);
2540 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2541 * rather silly way of saying "true if both are nonnull, else null".
2543 if (te1IsNull || te2IsNull)
2545 PG_RETURN_BOOL(true);
2554 timetz_time(PG_FUNCTION_ARGS)
2556 TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
2559 /* swallow the time zone and just return the time */
2560 result = timetz->time;
2562 PG_RETURN_TIMEADT(result);
2567 time_timetz(PG_FUNCTION_ARGS)
2569 TimeADT time = PG_GETARG_TIMEADT(0);
2576 GetCurrentDateTime(tm);
2577 time2tm(time, tm, &fsec);
2578 tz = DetermineTimeZoneOffset(tm, session_timezone);
2580 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2582 result->time = time;
2585 PG_RETURN_TIMETZADT_P(result);
2589 /* timestamptz_timetz()
2590 * Convert timestamp to timetz data type.
2593 timestamptz_timetz(PG_FUNCTION_ARGS)
2595 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2602 if (TIMESTAMP_NOT_FINITE(timestamp))
2605 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2607 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2608 errmsg("timestamp out of range")));
2610 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2612 tm2timetz(tm, fsec, tz, result);
2614 PG_RETURN_TIMETZADT_P(result);
2618 /* datetimetz_timestamptz()
2619 * Convert date and timetz to timestamp with time zone data type.
2620 * Timestamp is stored in GMT, so add the time zone
2621 * stored with the timetz to the result.
2622 * - thomas 2000-03-10
2625 datetimetz_timestamptz(PG_FUNCTION_ARGS)
2627 DateADT date = PG_GETARG_DATEADT(0);
2628 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2631 if (DATE_IS_NOBEGIN(date))
2632 TIMESTAMP_NOBEGIN(result);
2633 else if (DATE_IS_NOEND(date))
2634 TIMESTAMP_NOEND(result);
2638 * Date's range is wider than timestamp's, so check for boundaries.
2639 * Since dates have the same minimum values as timestamps, only upper
2640 * boundary need be checked for overflow.
2642 if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
2644 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2645 errmsg("date out of range for timestamp")));
2646 result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
2649 * Since it is possible to go beyond allowed timestamptz range because
2650 * of time zone, check for allowed timestamp range after adding tz.
2652 if (!IS_VALID_TIMESTAMP(result))
2654 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2655 errmsg("date out of range for timestamp")));
2658 PG_RETURN_TIMESTAMP(result);
2663 * Extract specified field from time type.
2666 timetz_part(PG_FUNCTION_ARGS)
2668 text *units = PG_GETARG_TEXT_PP(0);
2669 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2675 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2676 VARSIZE_ANY_EXHDR(units),
2679 type = DecodeUnits(0, lowunits, &val);
2680 if (type == UNKNOWN_FIELD)
2681 type = DecodeSpecial(0, lowunits, &val);
2691 timetz2tm(time, tm, &fsec, &tz);
2701 result /= SECS_PER_MINUTE;
2702 FMODULO(result, dummy, (double) SECS_PER_MINUTE);
2707 FMODULO(dummy, result, (double) SECS_PER_HOUR);
2711 result = tm->tm_sec * 1000000.0 + fsec;
2715 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
2719 result = tm->tm_sec + fsec / 1000000.0;
2723 result = tm->tm_min;
2727 result = tm->tm_hour;
2736 case DTK_MILLENNIUM:
2739 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2740 errmsg("\"time with time zone\" units \"%s\" not recognized",
2745 else if (type == RESERV && val == DTK_EPOCH)
2747 result = time->time / 1000000.0 + time->zone;
2752 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2753 errmsg("\"time with time zone\" units \"%s\" not recognized",
2758 PG_RETURN_FLOAT8(result);
2762 * Encode time with time zone type with specified time zone.
2763 * Applies DST rules as of the current date.
2766 timetz_zone(PG_FUNCTION_ARGS)
2768 text *zone = PG_GETARG_TEXT_PP(0);
2769 TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
2772 char tzname[TZ_STRLEN_MAX + 1];
2779 * Look up the requested timezone. First we look in the timezone
2780 * abbreviation table (to handle cases like "EST"), and if that fails, we
2781 * look in the timezone database (to handle cases like
2782 * "America/New_York"). (This matches the order in which timestamp input
2783 * checks the cases; it's important because the timezone database unwisely
2784 * uses a few zone names that are identical to offset abbreviations.)
2786 text_to_cstring_buffer(zone, tzname, sizeof(tzname));
2788 /* DecodeTimezoneAbbrev requires lowercase input */
2789 lowzone = downcase_truncate_identifier(tzname,
2793 type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
2795 if (type == TZ || type == DTZ)
2797 /* fixed-offset abbreviation */
2800 else if (type == DYNTZ)
2802 /* dynamic-offset abbreviation, resolve using current time */
2803 pg_time_t now = (pg_time_t) time(NULL);
2806 tm = pg_localtime(&now, tzp);
2807 tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
2811 /* try it as a full zone name */
2812 tzp = pg_tzset(tzname);
2815 /* Get the offset-from-GMT that is valid today for the zone */
2816 pg_time_t now = (pg_time_t) time(NULL);
2819 tm = pg_localtime(&now, tzp);
2820 tz = -tm->tm_gmtoff;
2825 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2826 errmsg("time zone \"%s\" not recognized", tzname)));
2827 tz = 0; /* keep compiler quiet */
2831 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2833 result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
2834 while (result->time < INT64CONST(0))
2835 result->time += USECS_PER_DAY;
2836 while (result->time >= USECS_PER_DAY)
2837 result->time -= USECS_PER_DAY;
2841 PG_RETURN_TIMETZADT_P(result);
2845 * Encode time with time zone type with specified time interval as time zone.
2848 timetz_izone(PG_FUNCTION_ARGS)
2850 Interval *zone = PG_GETARG_INTERVAL_P(0);
2851 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2855 if (zone->month != 0 || zone->day != 0)
2857 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2858 errmsg("interval time zone \"%s\" must not include months or days",
2859 DatumGetCString(DirectFunctionCall1(interval_out,
2860 PointerGetDatum(zone))))));
2862 tz = -(zone->time / USECS_PER_SEC);
2864 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2866 result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
2867 while (result->time < INT64CONST(0))
2868 result->time += USECS_PER_DAY;
2869 while (result->time >= USECS_PER_DAY)
2870 result->time -= USECS_PER_DAY;
2874 PG_RETURN_TIMETZADT_P(result);