1 /*-------------------------------------------------------------------------
4 * implements DATE and TIME data types specified in SQL-92 standard
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.71 2002/09/03 19:41:28 tgl Exp $
13 *-------------------------------------------------------------------------
23 #include "access/hash.h"
24 #include "miscadmin.h"
25 #include "utils/builtins.h"
26 #include "utils/date.h"
27 #include "utils/nabstime.h"
28 #include "utils/timestamp.h"
31 int time2tm(TimeADT time, struct tm * tm, fsec_t *fsec);
32 int timetz2tm(TimeTzADT *time, struct tm * tm, fsec_t *fsec, int *tzp);
33 int tm2time(struct tm * tm, fsec_t fsec, TimeADT *result);
34 int tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
35 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
37 /*****************************************************************************
39 *****************************************************************************/
43 * Given date text string, convert to internal date format.
46 date_in(PG_FUNCTION_ARGS)
48 char *str = PG_GETARG_CSTRING(0);
56 char *field[MAXDATEFIELDS];
57 int ftype[MAXDATEFIELDS];
58 char lowstr[MAXDATELEN + 1];
60 if (strlen(str) >= sizeof(lowstr))
61 elog(ERROR, "Bad date external representation (too long) '%s'", str);
63 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
64 || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0))
65 elog(ERROR, "Bad date external representation '%s'", str);
73 elog(ERROR, "Date CURRENT no longer supported"
74 "\n\tdate_in() internal coding error");
75 GetCurrentDateTime(tm);
83 elog(ERROR, "Unrecognized date external representation '%s'", str);
86 date = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
88 PG_RETURN_DATEADT(date);
92 * Given internal format date, convert to text string.
95 date_out(PG_FUNCTION_ARGS)
97 DateADT date = PG_GETARG_DATEADT(0);
101 char buf[MAXDATELEN + 1];
103 j2date((date + date2j(2000, 1, 1)),
104 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
106 EncodeDateOnly(tm, DateStyle, buf);
108 result = pstrdup(buf);
109 PG_RETURN_CSTRING(result);
113 date_eq(PG_FUNCTION_ARGS)
115 DateADT dateVal1 = PG_GETARG_DATEADT(0);
116 DateADT dateVal2 = PG_GETARG_DATEADT(1);
118 PG_RETURN_BOOL(dateVal1 == dateVal2);
122 date_ne(PG_FUNCTION_ARGS)
124 DateADT dateVal1 = PG_GETARG_DATEADT(0);
125 DateADT dateVal2 = PG_GETARG_DATEADT(1);
127 PG_RETURN_BOOL(dateVal1 != dateVal2);
131 date_lt(PG_FUNCTION_ARGS)
133 DateADT dateVal1 = PG_GETARG_DATEADT(0);
134 DateADT dateVal2 = PG_GETARG_DATEADT(1);
136 PG_RETURN_BOOL(dateVal1 < dateVal2);
140 date_le(PG_FUNCTION_ARGS)
142 DateADT dateVal1 = PG_GETARG_DATEADT(0);
143 DateADT dateVal2 = PG_GETARG_DATEADT(1);
145 PG_RETURN_BOOL(dateVal1 <= dateVal2);
149 date_gt(PG_FUNCTION_ARGS)
151 DateADT dateVal1 = PG_GETARG_DATEADT(0);
152 DateADT dateVal2 = PG_GETARG_DATEADT(1);
154 PG_RETURN_BOOL(dateVal1 > dateVal2);
158 date_ge(PG_FUNCTION_ARGS)
160 DateADT dateVal1 = PG_GETARG_DATEADT(0);
161 DateADT dateVal2 = PG_GETARG_DATEADT(1);
163 PG_RETURN_BOOL(dateVal1 >= dateVal2);
167 date_cmp(PG_FUNCTION_ARGS)
169 DateADT dateVal1 = PG_GETARG_DATEADT(0);
170 DateADT dateVal2 = PG_GETARG_DATEADT(1);
172 if (dateVal1 < dateVal2)
174 else if (dateVal1 > dateVal2)
180 date_larger(PG_FUNCTION_ARGS)
182 DateADT dateVal1 = PG_GETARG_DATEADT(0);
183 DateADT dateVal2 = PG_GETARG_DATEADT(1);
185 PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
189 date_smaller(PG_FUNCTION_ARGS)
191 DateADT dateVal1 = PG_GETARG_DATEADT(0);
192 DateADT dateVal2 = PG_GETARG_DATEADT(1);
194 PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
197 /* Compute difference between two dates in days.
200 date_mi(PG_FUNCTION_ARGS)
202 DateADT dateVal1 = PG_GETARG_DATEADT(0);
203 DateADT dateVal2 = PG_GETARG_DATEADT(1);
205 PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
208 /* Add a number of days to a date, giving a new date.
209 * Must handle both positive and negative numbers of days.
212 date_pli(PG_FUNCTION_ARGS)
214 DateADT dateVal = PG_GETARG_DATEADT(0);
215 int32 days = PG_GETARG_INT32(1);
217 PG_RETURN_DATEADT(dateVal + days);
220 /* Subtract a number of days from a date, giving a new date.
223 date_mii(PG_FUNCTION_ARGS)
225 DateADT dateVal = PG_GETARG_DATEADT(0);
226 int32 days = PG_GETARG_INT32(1);
228 PG_RETURN_DATEADT(dateVal - days);
232 /* date_pl_interval() and date_mi_interval() are probably
233 * better implmented by converting the input date
234 * to timestamp without time zone. So that is what we do
235 * in pg_proc.h - thomas 2002-03-11
238 /* Add an interval to a date, giving a new date.
239 * Must handle both positive and negative intervals.
242 date_pl_interval(PG_FUNCTION_ARGS)
244 DateADT dateVal = PG_GETARG_DATEADT(0);
245 Interval *span = PG_GETARG_INTERVAL_P(1);
249 if (span->month != 0)
251 j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
252 tm->tm_mon += span->month;
253 dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
256 dateVal += (span->time / 86400e0);
258 PG_RETURN_DATEADT(dateVal);
261 /* Subtract an interval from a date, giving a new date.
262 * Must handle both positive and negative intervals.
265 date_mi_interval(PG_FUNCTION_ARGS)
267 DateADT dateVal = PG_GETARG_DATEADT(0);
268 Interval *span = PG_GETARG_INTERVAL_P(1);
272 if (span->month != 0)
274 j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
275 tm->tm_mon -= span->month;
276 dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
279 dateVal -= (span->time / 86400e0);
281 PG_RETURN_DATEADT(dateVal);
286 * Convert date to timestamp data type.
289 date_timestamp(PG_FUNCTION_ARGS)
291 DateADT dateVal = PG_GETARG_DATEADT(0);
294 #ifdef HAVE_INT64_TIMESTAMP
295 /* date is days since 2000, timestamp is microseconds since same... */
296 result = dateVal * INT64CONST(86400000000);
298 /* date is days since 2000, timestamp is seconds since same... */
299 result = dateVal * 86400.0;
302 PG_RETURN_TIMESTAMP(result);
307 * Convert timestamp to date data type.
310 timestamp_date(PG_FUNCTION_ARGS)
312 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
315 if (TIMESTAMP_NOT_FINITE(timestamp))
318 #ifdef HAVE_INT64_TIMESTAMP
319 /* Microseconds to days */
320 result = (timestamp / INT64CONST(86400000000));
322 /* Seconds to days */
323 result = (timestamp / 86400.0);
326 PG_RETURN_DATEADT(result);
330 /* date_timestamptz()
331 * Convert date to timestamp with time zone data type.
334 date_timestamptz(PG_FUNCTION_ARGS)
336 DateADT dateVal = PG_GETARG_DATEADT(0);
341 j2date((dateVal + date2j(2000, 1, 1)),
342 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
344 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
351 tz = DetermineLocalTimeZone(tm);
353 #ifdef HAVE_INT64_TIMESTAMP
354 result = (dateVal * INT64CONST(86400000000))
355 + (tz * INT64CONST(1000000));
357 result = dateVal * 86400.0 + tz;
362 /* Outside of range for timezone support, so assume UTC */
363 #ifdef HAVE_INT64_TIMESTAMP
364 result = (dateVal * INT64CONST(86400000000));
366 result = dateVal * 86400.0;
370 PG_RETURN_TIMESTAMP(result);
374 /* timestamptz_date()
375 * Convert timestamp with time zone to date data type.
378 timestamptz_date(PG_FUNCTION_ARGS)
380 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
388 if (TIMESTAMP_NOT_FINITE(timestamp))
391 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
392 elog(ERROR, "Unable to convert timestamp to date");
394 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
396 PG_RETURN_DATEADT(result);
401 * Convert abstime to date data type.
404 abstime_date(PG_FUNCTION_ARGS)
406 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
414 case INVALID_ABSTIME:
415 case NOSTART_ABSTIME:
417 elog(ERROR, "Unable to convert reserved abstime value to date");
420 * pretend to drop through to make compiler think that result
425 abstime2tm(abstime, &tz, tm, NULL);
426 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
430 PG_RETURN_DATEADT(result);
435 * Convert date to text data type.
438 date_text(PG_FUNCTION_ARGS)
440 /* Input is a Date, but may as well leave it in Datum form */
441 Datum date = PG_GETARG_DATUM(0);
446 str = DatumGetCString(DirectFunctionCall1(date_out, date));
448 len = (strlen(str) + VARHDRSZ);
450 result = palloc(len);
452 VARATT_SIZEP(result) = len;
453 memmove(VARDATA(result), str, (len - VARHDRSZ));
457 PG_RETURN_TEXT_P(result);
462 * Convert text string to date.
463 * Text type is not null terminated, so use temporary string
464 * then call the standard input routine.
467 text_date(PG_FUNCTION_ARGS)
469 text *str = PG_GETARG_TEXT_P(0);
473 dstr[MAXDATELEN + 1];
475 if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
476 elog(ERROR, "Bad date external representation (too long)");
480 for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
484 return DirectFunctionCall1(date_in,
485 CStringGetDatum(dstr));
489 /*****************************************************************************
491 *****************************************************************************/
494 time_in(PG_FUNCTION_ARGS)
496 char *str = PG_GETARG_CSTRING(0);
498 Oid typelem = PG_GETARG_OID(1);
500 int32 typmod = PG_GETARG_INT32(2);
506 char lowstr[MAXDATELEN + 1];
507 char *field[MAXDATEFIELDS];
509 int ftype[MAXDATEFIELDS];
511 if (strlen(str) >= sizeof(lowstr))
512 elog(ERROR, "Bad time external representation (too long) '%s'", str);
514 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
515 || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, NULL) != 0))
516 elog(ERROR, "Bad time external representation '%s'", str);
518 tm2time(tm, fsec, &result);
519 AdjustTimeForTypmod(&result, typmod);
521 PG_RETURN_TIMEADT(result);
525 * Convert a tm structure to a time data type.
528 tm2time(struct tm * tm, fsec_t fsec, TimeADT *result)
530 #ifdef HAVE_INT64_TIMESTAMP
531 *result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
532 * INT64CONST(1000000)) + fsec);
534 *result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
540 * Convert time data type to POSIX time structure.
541 * For dates within the system-supported time_t range, convert to the
542 * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
545 time2tm(TimeADT time, struct tm *tm, fsec_t *fsec)
547 #ifdef HAVE_INT64_TIMESTAMP
548 tm->tm_hour = (time / INT64CONST(3600000000));
549 time -= (tm->tm_hour * INT64CONST(3600000000));
550 tm->tm_min = (time / INT64CONST(60000000));
551 time -= (tm->tm_min * INT64CONST(60000000));
552 tm->tm_sec = (time / INT64CONST(1000000));
553 time -= (tm->tm_sec * INT64CONST(1000000));
559 TMODULO(trem, tm->tm_hour, 3600e0);
560 TMODULO(trem, tm->tm_min, 60e0);
561 TMODULO(trem, tm->tm_sec, 1e0);
569 time_out(PG_FUNCTION_ARGS)
571 TimeADT time = PG_GETARG_TIMEADT(0);
576 char buf[MAXDATELEN + 1];
578 time2tm(time, tm, &fsec);
579 EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
581 result = pstrdup(buf);
582 PG_RETURN_CSTRING(result);
586 * Adjust time type for specified scale factor.
587 * Used by PostgreSQL type system to stuff columns.
590 time_scale(PG_FUNCTION_ARGS)
592 TimeADT time = PG_GETARG_TIMEADT(0);
593 int32 typmod = PG_GETARG_INT32(1);
597 AdjustTimeForTypmod(&result, typmod);
599 PG_RETURN_TIMEADT(result);
602 /* AdjustTimeForTypmod()
603 * Force the precision of the time value to a specified value.
604 * Uses *exactly* the same code as in AdjustTimestampForTypemod()
605 * but we make a separate copy because those types do not
606 * have a fundamental tie together but rather a coincidence of
607 * implementation. - thomas
610 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
612 #ifdef HAVE_INT64_TIMESTAMP
613 static const int64 TimeScales[MAX_TIMESTAMP_PRECISION+1] = {
623 static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION+1] = {
633 static const double TimeScales[MAX_TIMESTAMP_PRECISION+1] = {
643 static const double TimeOffsets[MAX_TIMESTAMP_PRECISION+1] = {
654 if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))
656 #ifdef HAVE_INT64_TIMESTAMP
657 /* we have different truncation behavior depending on sign */
658 if (*time >= INT64CONST(0))
660 *time = ((*time / TimeScales[typmod])
661 * TimeScales[typmod]);
665 *time = (((*time + TimeOffsets[typmod]) / TimeScales[typmod])
666 * TimeScales[typmod]);
669 /* we have different truncation behavior depending on sign */
672 *time = (rint(((double) *time) * TimeScales[typmod])
673 / TimeScales[typmod]);
677 /* Scale and truncate first, then add to help the rounding behavior */
678 *time = (rint((((double) *time) * TimeScales[typmod]) + TimeOffsets[typmod])
679 / TimeScales[typmod]);
689 time_eq(PG_FUNCTION_ARGS)
691 TimeADT time1 = PG_GETARG_TIMEADT(0);
692 TimeADT time2 = PG_GETARG_TIMEADT(1);
694 PG_RETURN_BOOL(time1 == time2);
698 time_ne(PG_FUNCTION_ARGS)
700 TimeADT time1 = PG_GETARG_TIMEADT(0);
701 TimeADT time2 = PG_GETARG_TIMEADT(1);
703 PG_RETURN_BOOL(time1 != time2);
707 time_lt(PG_FUNCTION_ARGS)
709 TimeADT time1 = PG_GETARG_TIMEADT(0);
710 TimeADT time2 = PG_GETARG_TIMEADT(1);
712 PG_RETURN_BOOL(time1 < time2);
716 time_le(PG_FUNCTION_ARGS)
718 TimeADT time1 = PG_GETARG_TIMEADT(0);
719 TimeADT time2 = PG_GETARG_TIMEADT(1);
721 PG_RETURN_BOOL(time1 <= time2);
725 time_gt(PG_FUNCTION_ARGS)
727 TimeADT time1 = PG_GETARG_TIMEADT(0);
728 TimeADT time2 = PG_GETARG_TIMEADT(1);
730 PG_RETURN_BOOL(time1 > time2);
734 time_ge(PG_FUNCTION_ARGS)
736 TimeADT time1 = PG_GETARG_TIMEADT(0);
737 TimeADT time2 = PG_GETARG_TIMEADT(1);
739 PG_RETURN_BOOL(time1 >= time2);
743 time_cmp(PG_FUNCTION_ARGS)
745 TimeADT time1 = PG_GETARG_TIMEADT(0);
746 TimeADT time2 = PG_GETARG_TIMEADT(1);
756 time_larger(PG_FUNCTION_ARGS)
758 TimeADT time1 = PG_GETARG_TIMEADT(0);
759 TimeADT time2 = PG_GETARG_TIMEADT(1);
761 PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
765 time_smaller(PG_FUNCTION_ARGS)
767 TimeADT time1 = PG_GETARG_TIMEADT(0);
768 TimeADT time2 = PG_GETARG_TIMEADT(1);
770 PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
773 /* overlaps_time() --- implements the SQL92 OVERLAPS operator.
775 * Algorithm is per SQL92 spec. This is much harder than you'd think
776 * because the spec requires us to deliver a non-null answer in some cases
777 * where some of the inputs are null.
780 overlaps_time(PG_FUNCTION_ARGS)
783 * The arguments are TimeADT, but we leave them as generic Datums to
784 * avoid dereferencing nulls (TimeADT is pass-by-reference!)
786 Datum ts1 = PG_GETARG_DATUM(0);
787 Datum te1 = PG_GETARG_DATUM(1);
788 Datum ts2 = PG_GETARG_DATUM(2);
789 Datum te2 = PG_GETARG_DATUM(3);
790 bool ts1IsNull = PG_ARGISNULL(0);
791 bool te1IsNull = PG_ARGISNULL(1);
792 bool ts2IsNull = PG_ARGISNULL(2);
793 bool te2IsNull = PG_ARGISNULL(3);
795 #define TIMEADT_GT(t1,t2) \
796 (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
797 #define TIMEADT_LT(t1,t2) \
798 (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
801 * If both endpoints of interval 1 are null, the result is null
802 * (unknown). If just one endpoint is null, take ts1 as the non-null
803 * one. Otherwise, take ts1 as the lesser endpoint.
809 /* swap null for non-null */
815 if (TIMEADT_GT(ts1, te1))
824 /* Likewise for interval 2. */
829 /* swap null for non-null */
835 if (TIMEADT_GT(ts2, te2))
845 * At this point neither ts1 nor ts2 is null, so we can consider three
846 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
848 if (TIMEADT_GT(ts1, ts2))
851 * This case is ts1 < te2 OR te1 < te2, which may look redundant
852 * but in the presence of nulls it's not quite completely so.
856 if (TIMEADT_LT(ts1, te2))
857 PG_RETURN_BOOL(true);
862 * If te1 is not null then we had ts1 <= te1 above, and we just
863 * found ts1 >= te2, hence te1 >= te2.
865 PG_RETURN_BOOL(false);
867 else if (TIMEADT_LT(ts1, ts2))
869 /* This case is ts2 < te1 OR te2 < te1 */
872 if (TIMEADT_LT(ts2, te1))
873 PG_RETURN_BOOL(true);
878 * If te2 is not null then we had ts2 <= te2 above, and we just
879 * found ts2 >= te1, hence te2 >= te1.
881 PG_RETURN_BOOL(false);
886 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
887 * rather silly way of saying "true if both are nonnull, else
890 if (te1IsNull || te2IsNull)
892 PG_RETURN_BOOL(true);
900 * Convert timestamp to time data type.
903 timestamp_time(PG_FUNCTION_ARGS)
905 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
911 if (TIMESTAMP_NOT_FINITE(timestamp))
914 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
915 elog(ERROR, "Unable to convert timestamp to time");
917 #ifdef HAVE_INT64_TIMESTAMP
918 /* Could also do this with
919 * time = (timestamp / 86400000000 * 86400000000) - timestamp;
921 result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
922 * INT64CONST(1000000)) + fsec);
924 result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
927 PG_RETURN_TIMEADT(result);
930 /* timestamptz_time()
931 * Convert timestamptz to time data type.
934 timestamptz_time(PG_FUNCTION_ARGS)
936 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
944 if (TIMESTAMP_NOT_FINITE(timestamp))
947 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
948 elog(ERROR, "Unable to convert timestamptz to time");
950 #ifdef HAVE_INT64_TIMESTAMP
951 /* Could also do this with
952 * time = (timestamp / 86400000000 * 86400000000) - timestamp;
954 result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
955 * INT64CONST(1000000)) + fsec);
957 result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
960 PG_RETURN_TIMEADT(result);
963 /* datetime_timestamp()
964 * Convert date and time to timestamp data type.
967 datetime_timestamp(PG_FUNCTION_ARGS)
969 DateADT date = PG_GETARG_DATEADT(0);
970 TimeADT time = PG_GETARG_TIMEADT(1);
973 result = DatumGetTimestamp(DirectFunctionCall1(date_timestamp,
974 DateADTGetDatum(date)));
977 PG_RETURN_TIMESTAMP(result);
981 * Convert time to interval data type.
984 time_interval(PG_FUNCTION_ARGS)
986 TimeADT time = PG_GETARG_TIMEADT(0);
989 result = (Interval *) palloc(sizeof(Interval));
994 PG_RETURN_INTERVAL_P(result);
998 * Convert interval to time data type.
1001 interval_time(PG_FUNCTION_ARGS)
1003 Interval *span = PG_GETARG_INTERVAL_P(0);
1006 #ifdef HAVE_INT64_TIMESTAMP
1007 result = span->time;
1008 if ((result >= INT64CONST(86400000000))
1009 || (result <= INT64CONST(-86400000000)))
1010 result -= (result / INT64CONST(1000000) * INT64CONST(1000000));
1014 result = span->time;
1015 TMODULO(result, span1.time, 86400e0);
1018 PG_RETURN_TIMEADT(result);
1022 * Subtract two times to produce an interval.
1025 time_mi_time(PG_FUNCTION_ARGS)
1027 TimeADT time1 = PG_GETARG_TIMEADT(0);
1028 TimeADT time2 = PG_GETARG_TIMEADT(1);
1031 result = (Interval *) palloc(sizeof(Interval));
1033 result->time = (time1 - time2);
1036 PG_RETURN_INTERVAL_P(result);
1039 /* time_pl_interval()
1040 * Add interval to time.
1043 time_pl_interval(PG_FUNCTION_ARGS)
1045 TimeADT time = PG_GETARG_TIMEADT(0);
1046 Interval *span = PG_GETARG_INTERVAL_P(1);
1049 #ifdef HAVE_INT64_TIMESTAMP
1050 result = (time + span->time);
1051 result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
1052 if (result < INT64CONST(0))
1053 result += INT64CONST(86400000000);
1057 result = (time + span->time);
1058 TMODULO(result, time1, 86400e0);
1063 PG_RETURN_TIMEADT(result);
1066 /* time_mi_interval()
1067 * Subtract interval from time.
1070 time_mi_interval(PG_FUNCTION_ARGS)
1072 TimeADT time = PG_GETARG_TIMEADT(0);
1073 Interval *span = PG_GETARG_INTERVAL_P(1);
1076 #ifdef HAVE_INT64_TIMESTAMP
1077 result = (time - span->time);
1078 result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
1079 if (result < INT64CONST(0))
1080 result += INT64CONST(86400000000);
1084 result = (time - span->time);
1085 TMODULO(result, time1, 86400e0);
1090 PG_RETURN_TIMEADT(result);
1093 /* interval_pl_time()
1094 * Add time to interval.
1097 interval_pl_time(PG_FUNCTION_ARGS)
1099 Datum span = PG_GETARG_DATUM(0);
1100 Datum time = PG_GETARG_DATUM(1);
1102 return DirectFunctionCall2(time_pl_interval, time, span);
1107 * Convert time to text data type.
1110 time_text(PG_FUNCTION_ARGS)
1112 /* Input is a Time, but may as well leave it in Datum form */
1113 Datum time = PG_GETARG_DATUM(0);
1118 str = DatumGetCString(DirectFunctionCall1(time_out, time));
1120 len = (strlen(str) + VARHDRSZ);
1122 result = palloc(len);
1124 VARATT_SIZEP(result) = len;
1125 memmove(VARDATA(result), str, (len - VARHDRSZ));
1129 PG_RETURN_TEXT_P(result);
1134 * Convert text string to time.
1135 * Text type is not null terminated, so use temporary string
1136 * then call the standard input routine.
1139 text_time(PG_FUNCTION_ARGS)
1141 text *str = PG_GETARG_TEXT_P(0);
1145 dstr[MAXDATELEN + 1];
1147 if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
1148 elog(ERROR, "Bad time external representation (too long)");
1152 for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
1156 return DirectFunctionCall3(time_in,
1157 CStringGetDatum(dstr),
1158 ObjectIdGetDatum(InvalidOid),
1163 * Extract specified field from time type.
1166 time_part(PG_FUNCTION_ARGS)
1168 text *units = PG_GETARG_TEXT_P(0);
1169 TimeADT time = PG_GETARG_TIMEADT(1);
1176 lowunits[MAXDATELEN + 1];
1178 if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
1179 elog(ERROR, "TIME units '%s' not recognized",
1180 DatumGetCString(DirectFunctionCall1(textout,
1181 PointerGetDatum(units))));
1182 up = VARDATA(units);
1184 for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
1185 *lp++ = tolower((unsigned char) *up++);
1188 type = DecodeUnits(0, lowunits, &val);
1189 if (type == UNKNOWN_FIELD)
1190 type = DecodeSpecial(0, lowunits, &val);
1198 time2tm(time, tm, &fsec);
1203 #ifdef HAVE_INT64_TIMESTAMP
1204 result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
1206 result = ((tm->tm_sec + fsec) * 1000000);
1211 #ifdef HAVE_INT64_TIMESTAMP
1212 result = ((tm->tm_sec * INT64CONST(1000))
1213 + (fsec / INT64CONST(1000)));
1215 result = ((tm->tm_sec + fsec) * 1000);
1220 #ifdef HAVE_INT64_TIMESTAMP
1221 result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
1223 result = (tm->tm_sec + fsec);
1228 result = tm->tm_min;
1232 result = tm->tm_hour;
1244 case DTK_MILLENNIUM:
1246 elog(ERROR, "TIME units '%s' not supported",
1247 DatumGetCString(DirectFunctionCall1(textout,
1248 PointerGetDatum(units))));
1252 else if ((type == RESERV) && (val == DTK_EPOCH))
1254 #ifdef HAVE_INT64_TIMESTAMP
1255 result = (time / 1000000e0);
1262 elog(ERROR, "TIME units '%s' not recognized",
1263 DatumGetCString(DirectFunctionCall1(textout,
1264 PointerGetDatum(units))));
1268 PG_RETURN_FLOAT8(result);
1272 /*****************************************************************************
1273 * Time With Time Zone ADT
1274 *****************************************************************************/
1277 * Convert a tm structure to a time data type.
1280 tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
1282 #ifdef HAVE_INT64_TIMESTAMP
1283 result->time = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
1284 * INT64CONST(1000000)) + fsec);
1286 result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
1294 timetz_in(PG_FUNCTION_ARGS)
1296 char *str = PG_GETARG_CSTRING(0);
1299 Oid typelem = PG_GETARG_OID(1);
1301 int32 typmod = PG_GETARG_INT32(2);
1308 char lowstr[MAXDATELEN + 1];
1309 char *field[MAXDATEFIELDS];
1311 int ftype[MAXDATEFIELDS];
1313 if (strlen(str) >= sizeof(lowstr))
1314 elog(ERROR, "Bad time with time zone"
1315 " external representation (too long) '%s'", str);
1317 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
1318 || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
1319 elog(ERROR, "Bad time external representation '%s'", str);
1321 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1322 tm2timetz(tm, fsec, tz, result);
1323 AdjustTimeForTypmod(&(result->time), typmod);
1325 PG_RETURN_TIMETZADT_P(result);
1329 timetz_out(PG_FUNCTION_ARGS)
1331 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1337 char buf[MAXDATELEN + 1];
1339 timetz2tm(time, tm, &fsec, &tz);
1340 EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
1342 result = pstrdup(buf);
1343 PG_RETURN_CSTRING(result);
1347 * Convert TIME WITH TIME ZONE data type to POSIX time structure.
1348 * For dates within the system-supported time_t range, convert to the
1349 * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
1352 timetz2tm(TimeTzADT *time, struct tm *tm, fsec_t *fsec, int *tzp)
1354 #ifdef HAVE_INT64_TIMESTAMP
1355 tm->tm_hour = (time->time / INT64CONST(3600000000));
1356 time->time -= (tm->tm_hour * INT64CONST(3600000000));
1357 tm->tm_min = (time->time / INT64CONST(60000000));
1358 time->time -= (tm->tm_min * INT64CONST(60000000));
1359 tm->tm_sec = (time->time / INT64CONST(1000000));
1360 *fsec = (time->time - (tm->tm_sec * INT64CONST(1000000)));
1365 TMODULO(trem, tm->tm_hour, 3600e0);
1366 TMODULO(trem, tm->tm_min, 60e0);
1367 TMODULO(trem, tm->tm_sec, 1e0);
1378 * Adjust time type for specified scale factor.
1379 * Used by PostgreSQL type system to stuff columns.
1382 timetz_scale(PG_FUNCTION_ARGS)
1384 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1385 int32 typmod = PG_GETARG_INT32(1);
1388 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1390 result->time = time->time;
1391 result->zone = time->zone;
1393 AdjustTimeForTypmod(&(result->time), typmod);
1395 PG_RETURN_TIMETZADT_P(result);
1400 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
1405 /* Primary sort is by true (GMT-equivalent) time */
1406 t1 = time1->time + time1->zone;
1407 t2 = time2->time + time2->zone;
1415 * If same GMT time, sort by timezone; we only want to say that two
1416 * timetz's are equal if both the time and zone parts are equal.
1418 if (time1->zone > time2->zone)
1420 if (time1->zone < time2->zone)
1427 timetz_eq(PG_FUNCTION_ARGS)
1429 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1430 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1432 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
1436 timetz_ne(PG_FUNCTION_ARGS)
1438 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1439 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1441 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
1445 timetz_lt(PG_FUNCTION_ARGS)
1447 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1448 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1450 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
1454 timetz_le(PG_FUNCTION_ARGS)
1456 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1457 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1459 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
1463 timetz_gt(PG_FUNCTION_ARGS)
1465 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1466 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1468 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
1472 timetz_ge(PG_FUNCTION_ARGS)
1474 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1475 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1477 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
1481 timetz_cmp(PG_FUNCTION_ARGS)
1483 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1484 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1486 PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
1490 * timetz, being an unusual size, needs a specialized hash function.
1493 timetz_hash(PG_FUNCTION_ARGS)
1495 TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
1498 * Specify hash length as sizeof(double) + sizeof(int4), not as
1499 * sizeof(TimeTzADT), so that any garbage pad bytes in the structure
1500 * won't be included in the hash!
1502 return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->zone));
1506 timetz_larger(PG_FUNCTION_ARGS)
1508 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1509 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1511 if (DatumGetBool(DirectFunctionCall2(timetz_gt,
1512 TimeTzADTPGetDatum(time1),
1513 TimeTzADTPGetDatum(time2))))
1514 PG_RETURN_TIMETZADT_P(time1);
1515 PG_RETURN_TIMETZADT_P(time2);
1519 timetz_smaller(PG_FUNCTION_ARGS)
1521 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
1522 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
1524 if (DatumGetBool(DirectFunctionCall2(timetz_lt,
1525 TimeTzADTPGetDatum(time1),
1526 TimeTzADTPGetDatum(time2))))
1527 PG_RETURN_TIMETZADT_P(time1);
1528 PG_RETURN_TIMETZADT_P(time2);
1531 /* timetz_pl_interval()
1532 * Add interval to timetz.
1535 timetz_pl_interval(PG_FUNCTION_ARGS)
1537 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1538 Interval *span = PG_GETARG_INTERVAL_P(1);
1540 #ifndef HAVE_INT64_TIMESTAMP
1544 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1546 #ifdef HAVE_INT64_TIMESTAMP
1547 result->time = (time->time + span->time);
1548 result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
1549 if (result->time < INT64CONST(0))
1550 result->time += INT64CONST(86400000000);
1552 result->time = (time->time + span->time);
1553 TMODULO(result->time, time1.time, 86400e0);
1554 if (result->time < 0)
1555 result->time += 86400;
1558 result->zone = time->zone;
1560 PG_RETURN_TIMETZADT_P(result);
1563 /* timetz_mi_interval()
1564 * Subtract interval from timetz.
1567 timetz_mi_interval(PG_FUNCTION_ARGS)
1569 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1570 Interval *span = PG_GETARG_INTERVAL_P(1);
1572 #ifndef HAVE_INT64_TIMESTAMP
1576 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1578 #ifdef HAVE_INT64_TIMESTAMP
1579 result->time = (time->time - span->time);
1580 result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
1581 if (result->time < INT64CONST(0))
1582 result->time += INT64CONST(86400000000);
1584 result->time = (time->time - span->time);
1585 TMODULO(result->time, time1.time, 86400e0);
1586 if (result->time < 0)
1587 result->time += 86400;
1590 result->zone = time->zone;
1592 PG_RETURN_TIMETZADT_P(result);
1595 /* overlaps_timetz() --- implements the SQL92 OVERLAPS operator.
1597 * Algorithm is per SQL92 spec. This is much harder than you'd think
1598 * because the spec requires us to deliver a non-null answer in some cases
1599 * where some of the inputs are null.
1602 overlaps_timetz(PG_FUNCTION_ARGS)
1605 * The arguments are TimeTzADT *, but we leave them as generic Datums
1606 * for convenience of notation --- and to avoid dereferencing nulls.
1608 Datum ts1 = PG_GETARG_DATUM(0);
1609 Datum te1 = PG_GETARG_DATUM(1);
1610 Datum ts2 = PG_GETARG_DATUM(2);
1611 Datum te2 = PG_GETARG_DATUM(3);
1612 bool ts1IsNull = PG_ARGISNULL(0);
1613 bool te1IsNull = PG_ARGISNULL(1);
1614 bool ts2IsNull = PG_ARGISNULL(2);
1615 bool te2IsNull = PG_ARGISNULL(3);
1617 #define TIMETZ_GT(t1,t2) \
1618 DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
1619 #define TIMETZ_LT(t1,t2) \
1620 DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
1623 * If both endpoints of interval 1 are null, the result is null
1624 * (unknown). If just one endpoint is null, take ts1 as the non-null
1625 * one. Otherwise, take ts1 as the lesser endpoint.
1631 /* swap null for non-null */
1635 else if (!te1IsNull)
1637 if (TIMETZ_GT(ts1, te1))
1646 /* Likewise for interval 2. */
1651 /* swap null for non-null */
1655 else if (!te2IsNull)
1657 if (TIMETZ_GT(ts2, te2))
1667 * At this point neither ts1 nor ts2 is null, so we can consider three
1668 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1670 if (TIMETZ_GT(ts1, ts2))
1673 * This case is ts1 < te2 OR te1 < te2, which may look redundant
1674 * but in the presence of nulls it's not quite completely so.
1678 if (TIMETZ_LT(ts1, te2))
1679 PG_RETURN_BOOL(true);
1684 * If te1 is not null then we had ts1 <= te1 above, and we just
1685 * found ts1 >= te2, hence te1 >= te2.
1687 PG_RETURN_BOOL(false);
1689 else if (TIMETZ_LT(ts1, ts2))
1691 /* This case is ts2 < te1 OR te2 < te1 */
1694 if (TIMETZ_LT(ts2, te1))
1695 PG_RETURN_BOOL(true);
1700 * If te2 is not null then we had ts2 <= te2 above, and we just
1701 * found ts2 >= te1, hence te2 >= te1.
1703 PG_RETURN_BOOL(false);
1708 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1709 * rather silly way of saying "true if both are nonnull, else
1712 if (te1IsNull || te2IsNull)
1714 PG_RETURN_BOOL(true);
1723 timetz_time(PG_FUNCTION_ARGS)
1725 TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
1728 /* swallow the time zone and just return the time */
1729 result = timetz->time;
1731 PG_RETURN_TIMEADT(result);
1736 time_timetz(PG_FUNCTION_ARGS)
1738 TimeADT time = PG_GETARG_TIMEADT(0);
1745 GetCurrentDateTime(tm);
1746 time2tm(time, tm, &fsec);
1747 tz = DetermineLocalTimeZone(tm);
1749 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1751 result->time = time;
1754 PG_RETURN_TIMETZADT_P(result);
1758 /* timestamptz_timetz()
1759 * Convert timestamp to timetz data type.
1762 timestamptz_timetz(PG_FUNCTION_ARGS)
1764 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1772 if (TIMESTAMP_NOT_FINITE(timestamp))
1775 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
1776 elog(ERROR, "Unable to convert timestamptz to timetz");
1778 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1780 tm2timetz(tm, fsec, tz, result);
1782 PG_RETURN_TIMETZADT_P(result);
1786 /* datetimetz_timestamptz()
1787 * Convert date and timetz to timestamp with time zone data type.
1788 * Timestamp is stored in GMT, so add the time zone
1789 * stored with the timetz to the result.
1790 * - thomas 2000-03-10
1793 datetimetz_timestamptz(PG_FUNCTION_ARGS)
1795 DateADT date = PG_GETARG_DATEADT(0);
1796 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
1799 #ifdef HAVE_INT64_TIMESTAMP
1800 result = (((date * INT64CONST(86400000000)) + time->time)
1801 + (time->zone * INT64CONST(1000000)));
1803 result = (((date * 86400.0) + time->time) + time->zone);
1806 PG_RETURN_TIMESTAMP(result);
1811 * Convert timetz to text data type.
1814 timetz_text(PG_FUNCTION_ARGS)
1816 /* Input is a Timetz, but may as well leave it in Datum form */
1817 Datum timetz = PG_GETARG_DATUM(0);
1822 str = DatumGetCString(DirectFunctionCall1(timetz_out, timetz));
1824 len = (strlen(str) + VARHDRSZ);
1826 result = palloc(len);
1828 VARATT_SIZEP(result) = len;
1829 memmove(VARDATA(result), str, (len - VARHDRSZ));
1833 PG_RETURN_TEXT_P(result);
1838 * Convert text string to timetz.
1839 * Text type is not null terminated, so use temporary string
1840 * then call the standard input routine.
1843 text_timetz(PG_FUNCTION_ARGS)
1845 text *str = PG_GETARG_TEXT_P(0);
1849 dstr[MAXDATELEN + 1];
1851 if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
1852 elog(ERROR, "Bad timetz external representation (too long)");
1856 for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
1860 return DirectFunctionCall3(timetz_in,
1861 CStringGetDatum(dstr),
1862 ObjectIdGetDatum(InvalidOid),
1867 * Extract specified field from time type.
1870 timetz_part(PG_FUNCTION_ARGS)
1872 text *units = PG_GETARG_TEXT_P(0);
1873 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
1880 lowunits[MAXDATELEN + 1];
1882 if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
1883 elog(ERROR, "TIMETZ units '%s' not recognized",
1884 DatumGetCString(DirectFunctionCall1(textout,
1885 PointerGetDatum(units))));
1886 up = VARDATA(units);
1888 for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
1889 *lp++ = tolower((unsigned char) *up++);
1892 type = DecodeUnits(0, lowunits, &val);
1893 if (type == UNKNOWN_FIELD)
1894 type = DecodeSpecial(0, lowunits, &val);
1904 timetz2tm(time, tm, &fsec, &tz);
1914 TMODULO(result, dummy, 60e0);
1919 TMODULO(dummy, result, 3600e0);
1923 #ifdef HAVE_INT64_TIMESTAMP
1924 result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
1926 result = ((tm->tm_sec + fsec) * 1000000);
1931 #ifdef HAVE_INT64_TIMESTAMP
1932 result = ((tm->tm_sec * INT64CONST(1000))
1933 + (fsec / INT64CONST(1000)));
1935 result = ((tm->tm_sec + fsec) * 1000);
1940 #ifdef HAVE_INT64_TIMESTAMP
1941 result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
1943 result = (tm->tm_sec + fsec);
1948 result = tm->tm_min;
1952 result = tm->tm_hour;
1961 case DTK_MILLENNIUM:
1963 elog(ERROR, "TIMETZ units '%s' not supported",
1964 DatumGetCString(DirectFunctionCall1(textout,
1965 PointerGetDatum(units))));
1969 else if ((type == RESERV) && (val == DTK_EPOCH))
1971 #ifdef HAVE_INT64_TIMESTAMP
1972 result = ((time->time / 1000000e0) - time->zone);
1974 result = (time->time - time->zone);
1979 elog(ERROR, "TIMETZ units '%s' not recognized",
1980 DatumGetCString(DirectFunctionCall1(textout,
1981 PointerGetDatum(units))));
1985 PG_RETURN_FLOAT8(result);
1989 * Encode time with time zone type with specified time zone.
1992 timetz_zone(PG_FUNCTION_ARGS)
1994 text *zone = PG_GETARG_TEXT_P(0);
1995 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2004 lowzone[MAXDATELEN + 1];
2006 if (VARSIZE(zone) - VARHDRSZ > MAXDATELEN)
2007 elog(ERROR, "Time zone '%s' not recognized",
2008 DatumGetCString(DirectFunctionCall1(textout,
2009 PointerGetDatum(zone))));
2012 for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++)
2013 *lp++ = tolower((unsigned char) *up++);
2016 type = DecodeSpecial(0, lowzone, &val);
2018 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2020 if ((type == TZ) || (type == DTZ))
2023 #ifdef HAVE_INT64_TIMESTAMP
2024 time1 = (time->time - ((time->zone + tz) * INT64CONST(1000000)));
2025 result->time -= ((result->time / time1) * time1);
2026 if (result->time < INT64CONST(0))
2027 result->time += INT64CONST(86400000000);
2029 time1 = (time->time - time->zone + tz);
2030 TMODULO(result->time, time1, 86400e0);
2031 if (result->time < 0)
2032 result->time += 86400;
2039 elog(ERROR, "Time zone '%s' not recognized", lowzone);
2043 PG_RETURN_TIMETZADT_P(result);
2044 } /* timetz_zone() */
2047 * Encode time with time zone type with specified time interval as time zone.
2050 timetz_izone(PG_FUNCTION_ARGS)
2052 Interval *zone = PG_GETARG_INTERVAL_P(0);
2053 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2057 if (zone->month != 0)
2058 elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
2059 DatumGetCString(DirectFunctionCall1(interval_out,
2060 PointerGetDatum(zone))));
2062 #ifdef HAVE_INT64_TIMESTAMP
2063 tz = -(zone->time / INT64CONST(1000000));
2068 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2070 #ifdef HAVE_INT64_TIMESTAMP
2071 result->time = (time->time + ((time->zone - tz) * INT64CONST(1000000)));
2072 while (result->time < INT64CONST(0))
2073 result->time += INT64CONST(86400000000);
2074 while (result->time >= INT64CONST(86400000000))
2075 result->time -= INT64CONST(86400000000);
2077 result->time = (time->time + (time->zone - tz));
2078 while (result->time < 0)
2079 result->time += 86400;
2080 while (result->time >= 86400)
2081 result->time -= 86400;
2086 PG_RETURN_TIMETZADT_P(result);
2087 } /* timetz_izone() */