]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/date.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / date.c
1 /*-------------------------------------------------------------------------
2  *
3  * date.c
4  *        implements DATE and TIME data types specified in SQL standard
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994-5, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/utils/adt/date.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include <ctype.h>
19 #include <limits.h>
20 #include <float.h>
21 #include <time.h>
22
23 #include "access/hash.h"
24 #include "access/xact.h"
25 #include "libpq/pqformat.h"
26 #include "miscadmin.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/nabstime.h"
33 #include "utils/sortsupport.h"
34
35 /*
36  * gcc's -ffast-math switch breaks routines that expect exact results from
37  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
38  */
39 #ifdef __FAST_MATH__
40 #error -ffast-math is known to break this code
41 #endif
42
43
44 static int      time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
45 static int      timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
46 static int      tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
47 static int      tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
48 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
49
50
51 /* common code for timetypmodin and timetztypmodin */
52 static int32
53 anytime_typmodin(bool istz, ArrayType *ta)
54 {
55         int32      *tl;
56         int                     n;
57
58         tl = ArrayGetIntegerTypmods(ta, &n);
59
60         /*
61          * we're not too tense about good error message here because grammar
62          * shouldn't allow wrong number of modifiers for TIME
63          */
64         if (n != 1)
65                 ereport(ERROR,
66                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
67                                  errmsg("invalid type modifier")));
68
69         return anytime_typmod_check(istz, tl[0]);
70 }
71
72 /* exported so parse_expr.c can use it */
73 int32
74 anytime_typmod_check(bool istz, int32 typmod)
75 {
76         if (typmod < 0)
77                 ereport(ERROR,
78                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79                                  errmsg("TIME(%d)%s precision must not be negative",
80                                                 typmod, (istz ? " WITH TIME ZONE" : ""))));
81         if (typmod > MAX_TIME_PRECISION)
82         {
83                 ereport(WARNING,
84                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
85                                  errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
86                                                 typmod, (istz ? " WITH TIME ZONE" : ""),
87                                                 MAX_TIME_PRECISION)));
88                 typmod = MAX_TIME_PRECISION;
89         }
90
91         return typmod;
92 }
93
94 /* common code for timetypmodout and timetztypmodout */
95 static char *
96 anytime_typmodout(bool istz, int32 typmod)
97 {
98         const char *tz = istz ? " with time zone" : " without time zone";
99
100         if (typmod >= 0)
101                 return psprintf("(%d)%s", (int) typmod, tz);
102         else
103                 return psprintf("%s", tz);
104 }
105
106
107 /*****************************************************************************
108  *       Date ADT
109  *****************************************************************************/
110
111
112 /* date_in()
113  * Given date text string, convert to internal date format.
114  */
115 Datum
116 date_in(PG_FUNCTION_ARGS)
117 {
118         char       *str = PG_GETARG_CSTRING(0);
119         DateADT         date;
120         fsec_t          fsec;
121         struct pg_tm tt,
122                            *tm = &tt;
123         int                     tzp;
124         int                     dtype;
125         int                     nf;
126         int                     dterr;
127         char       *field[MAXDATEFIELDS];
128         int                     ftype[MAXDATEFIELDS];
129         char            workbuf[MAXDATELEN + 1];
130
131         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
132                                                   field, ftype, MAXDATEFIELDS, &nf);
133         if (dterr == 0)
134                 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
135         if (dterr != 0)
136                 DateTimeParseError(dterr, str, "date");
137
138         switch (dtype)
139         {
140                 case DTK_DATE:
141                         break;
142
143                 case DTK_CURRENT:
144                         ereport(ERROR,
145                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146                           errmsg("date/time value \"current\" is no longer supported")));
147
148                         GetCurrentDateTime(tm);
149                         break;
150
151                 case DTK_EPOCH:
152                         GetEpochTime(tm);
153                         break;
154
155                 case DTK_LATE:
156                         DATE_NOEND(date);
157                         PG_RETURN_DATEADT(date);
158
159                 case DTK_EARLY:
160                         DATE_NOBEGIN(date);
161                         PG_RETURN_DATEADT(date);
162
163                 default:
164                         DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
165                         break;
166         }
167
168         /* Prevent overflow in Julian-day routines */
169         if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
170                 ereport(ERROR,
171                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
172                                  errmsg("date out of range: \"%s\"", str)));
173
174         date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
175
176         /* Now check for just-out-of-range dates */
177         if (!IS_VALID_DATE(date))
178                 ereport(ERROR,
179                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
180                                  errmsg("date out of range: \"%s\"", str)));
181
182         PG_RETURN_DATEADT(date);
183 }
184
185 /* date_out()
186  * Given internal format date, convert to text string.
187  */
188 Datum
189 date_out(PG_FUNCTION_ARGS)
190 {
191         DateADT         date = PG_GETARG_DATEADT(0);
192         char       *result;
193         struct pg_tm tt,
194                            *tm = &tt;
195         char            buf[MAXDATELEN + 1];
196
197         if (DATE_NOT_FINITE(date))
198                 EncodeSpecialDate(date, buf);
199         else
200         {
201                 j2date(date + POSTGRES_EPOCH_JDATE,
202                            &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
203                 EncodeDateOnly(tm, DateStyle, buf);
204         }
205
206         result = pstrdup(buf);
207         PG_RETURN_CSTRING(result);
208 }
209
210 /*
211  *              date_recv                       - converts external binary format to date
212  */
213 Datum
214 date_recv(PG_FUNCTION_ARGS)
215 {
216         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
217         DateADT         result;
218
219         result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
220
221         /* Limit to the same range that date_in() accepts. */
222         if (DATE_NOT_FINITE(result))
223                  /* ok */ ;
224         else if (!IS_VALID_DATE(result))
225                 ereport(ERROR,
226                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
227                                  errmsg("date out of range")));
228
229         PG_RETURN_DATEADT(result);
230 }
231
232 /*
233  *              date_send                       - converts date to binary format
234  */
235 Datum
236 date_send(PG_FUNCTION_ARGS)
237 {
238         DateADT         date = PG_GETARG_DATEADT(0);
239         StringInfoData buf;
240
241         pq_begintypsend(&buf);
242         pq_sendint(&buf, date, sizeof(date));
243         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
244 }
245
246 /*
247  *              make_date                       - date constructor
248  */
249 Datum
250 make_date(PG_FUNCTION_ARGS)
251 {
252         struct pg_tm tm;
253         DateADT         date;
254         int                     dterr;
255         bool            bc = false;
256
257         tm.tm_year = PG_GETARG_INT32(0);
258         tm.tm_mon = PG_GETARG_INT32(1);
259         tm.tm_mday = PG_GETARG_INT32(2);
260
261         /* Handle negative years as BC */
262         if (tm.tm_year < 0)
263         {
264                 bc = true;
265                 tm.tm_year = -tm.tm_year;
266         }
267
268         dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
269
270         if (dterr != 0)
271                 ereport(ERROR,
272                                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
273                                  errmsg("date field value out of range: %d-%02d-%02d",
274                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
275
276         /* Prevent overflow in Julian-day routines */
277         if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
278                 ereport(ERROR,
279                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
280                                  errmsg("date out of range: %d-%02d-%02d",
281                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
282
283         date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
284
285         /* Now check for just-out-of-range dates */
286         if (!IS_VALID_DATE(date))
287                 ereport(ERROR,
288                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
289                                  errmsg("date out of range: %d-%02d-%02d",
290                                                 tm.tm_year, tm.tm_mon, tm.tm_mday)));
291
292         PG_RETURN_DATEADT(date);
293 }
294
295 /*
296  * Convert reserved date values to string.
297  */
298 void
299 EncodeSpecialDate(DateADT dt, char *str)
300 {
301         if (DATE_IS_NOBEGIN(dt))
302                 strcpy(str, EARLY);
303         else if (DATE_IS_NOEND(dt))
304                 strcpy(str, LATE);
305         else    /* shouldn't happen */
306                 elog(ERROR, "invalid argument for EncodeSpecialDate");
307 }
308
309
310 /*
311  * GetSQLCurrentDate -- implements CURRENT_DATE
312  */
313 DateADT
314 GetSQLCurrentDate(void)
315 {
316         TimestampTz ts;
317         struct pg_tm tt,
318                            *tm = &tt;
319         fsec_t          fsec;
320         int                     tz;
321
322         ts = GetCurrentTransactionStartTimestamp();
323
324         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
325                 ereport(ERROR,
326                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
327                                  errmsg("timestamp out of range")));
328
329         return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
330 }
331
332 /*
333  * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
334  */
335 TimeTzADT *
336 GetSQLCurrentTime(int32 typmod)
337 {
338         TimeTzADT  *result;
339         TimestampTz ts;
340         struct pg_tm tt,
341                            *tm = &tt;
342         fsec_t          fsec;
343         int                     tz;
344
345         ts = GetCurrentTransactionStartTimestamp();
346
347         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
348                 ereport(ERROR,
349                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
350                                  errmsg("timestamp out of range")));
351
352         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
353         tm2timetz(tm, fsec, tz, result);
354         AdjustTimeForTypmod(&(result->time), typmod);
355         return result;
356 }
357
358 /*
359  * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
360  */
361 TimeADT
362 GetSQLLocalTime(int32 typmod)
363 {
364         TimeADT         result;
365         TimestampTz ts;
366         struct pg_tm tt,
367                            *tm = &tt;
368         fsec_t          fsec;
369         int                     tz;
370
371         ts = GetCurrentTransactionStartTimestamp();
372
373         if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
374                 ereport(ERROR,
375                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
376                                  errmsg("timestamp out of range")));
377
378         tm2time(tm, fsec, &result);
379         AdjustTimeForTypmod(&result, typmod);
380         return result;
381 }
382
383
384 /*
385  * Comparison functions for dates
386  */
387
388 Datum
389 date_eq(PG_FUNCTION_ARGS)
390 {
391         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
392         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
393
394         PG_RETURN_BOOL(dateVal1 == dateVal2);
395 }
396
397 Datum
398 date_ne(PG_FUNCTION_ARGS)
399 {
400         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
401         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
402
403         PG_RETURN_BOOL(dateVal1 != dateVal2);
404 }
405
406 Datum
407 date_lt(PG_FUNCTION_ARGS)
408 {
409         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
410         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
411
412         PG_RETURN_BOOL(dateVal1 < dateVal2);
413 }
414
415 Datum
416 date_le(PG_FUNCTION_ARGS)
417 {
418         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
419         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
420
421         PG_RETURN_BOOL(dateVal1 <= dateVal2);
422 }
423
424 Datum
425 date_gt(PG_FUNCTION_ARGS)
426 {
427         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
428         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
429
430         PG_RETURN_BOOL(dateVal1 > dateVal2);
431 }
432
433 Datum
434 date_ge(PG_FUNCTION_ARGS)
435 {
436         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
437         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
438
439         PG_RETURN_BOOL(dateVal1 >= dateVal2);
440 }
441
442 Datum
443 date_cmp(PG_FUNCTION_ARGS)
444 {
445         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
446         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
447
448         if (dateVal1 < dateVal2)
449                 PG_RETURN_INT32(-1);
450         else if (dateVal1 > dateVal2)
451                 PG_RETURN_INT32(1);
452         PG_RETURN_INT32(0);
453 }
454
455 static int
456 date_fastcmp(Datum x, Datum y, SortSupport ssup)
457 {
458         DateADT         a = DatumGetDateADT(x);
459         DateADT         b = DatumGetDateADT(y);
460
461         if (a < b)
462                 return -1;
463         else if (a > b)
464                 return 1;
465         return 0;
466 }
467
468 Datum
469 date_sortsupport(PG_FUNCTION_ARGS)
470 {
471         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
472
473         ssup->comparator = date_fastcmp;
474         PG_RETURN_VOID();
475 }
476
477 Datum
478 date_finite(PG_FUNCTION_ARGS)
479 {
480         DateADT         date = PG_GETARG_DATEADT(0);
481
482         PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
483 }
484
485 Datum
486 date_larger(PG_FUNCTION_ARGS)
487 {
488         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
489         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
490
491         PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
492 }
493
494 Datum
495 date_smaller(PG_FUNCTION_ARGS)
496 {
497         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
498         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
499
500         PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
501 }
502
503 /* Compute difference between two dates in days.
504  */
505 Datum
506 date_mi(PG_FUNCTION_ARGS)
507 {
508         DateADT         dateVal1 = PG_GETARG_DATEADT(0);
509         DateADT         dateVal2 = PG_GETARG_DATEADT(1);
510
511         if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
512                 ereport(ERROR,
513                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
514                                  errmsg("cannot subtract infinite dates")));
515
516         PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
517 }
518
519 /* Add a number of days to a date, giving a new date.
520  * Must handle both positive and negative numbers of days.
521  */
522 Datum
523 date_pli(PG_FUNCTION_ARGS)
524 {
525         DateADT         dateVal = PG_GETARG_DATEADT(0);
526         int32           days = PG_GETARG_INT32(1);
527         DateADT         result;
528
529         if (DATE_NOT_FINITE(dateVal))
530                 PG_RETURN_DATEADT(dateVal);             /* can't change infinity */
531
532         result = dateVal + days;
533
534         /* Check for integer overflow and out-of-allowed-range */
535         if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
536                 !IS_VALID_DATE(result))
537                 ereport(ERROR,
538                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
539                                  errmsg("date out of range")));
540
541         PG_RETURN_DATEADT(result);
542 }
543
544 /* Subtract a number of days from a date, giving a new date.
545  */
546 Datum
547 date_mii(PG_FUNCTION_ARGS)
548 {
549         DateADT         dateVal = PG_GETARG_DATEADT(0);
550         int32           days = PG_GETARG_INT32(1);
551         DateADT         result;
552
553         if (DATE_NOT_FINITE(dateVal))
554                 PG_RETURN_DATEADT(dateVal);             /* can't change infinity */
555
556         result = dateVal - days;
557
558         /* Check for integer overflow and out-of-allowed-range */
559         if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
560                 !IS_VALID_DATE(result))
561                 ereport(ERROR,
562                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
563                                  errmsg("date out of range")));
564
565         PG_RETURN_DATEADT(result);
566 }
567
568 /*
569  * Internal routines for promoting date to timestamp and timestamp with
570  * time zone
571  */
572
573 static Timestamp
574 date2timestamp(DateADT dateVal)
575 {
576         Timestamp       result;
577
578         if (DATE_IS_NOBEGIN(dateVal))
579                 TIMESTAMP_NOBEGIN(result);
580         else if (DATE_IS_NOEND(dateVal))
581                 TIMESTAMP_NOEND(result);
582         else
583         {
584                 /*
585                  * Date's range is wider than timestamp's, so check for boundaries.
586                  * Since dates have the same minimum values as timestamps, only upper
587                  * boundary need be checked for overflow.
588                  */
589                 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
590                         ereport(ERROR,
591                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
592                                          errmsg("date out of range for timestamp")));
593
594                 /* date is days since 2000, timestamp is microseconds since same... */
595                 result = dateVal * USECS_PER_DAY;
596         }
597
598         return result;
599 }
600
601 static TimestampTz
602 date2timestamptz(DateADT dateVal)
603 {
604         TimestampTz result;
605         struct pg_tm tt,
606                            *tm = &tt;
607         int                     tz;
608
609         if (DATE_IS_NOBEGIN(dateVal))
610                 TIMESTAMP_NOBEGIN(result);
611         else if (DATE_IS_NOEND(dateVal))
612                 TIMESTAMP_NOEND(result);
613         else
614         {
615                 /*
616                  * Date's range is wider than timestamp's, so check for boundaries.
617                  * Since dates have the same minimum values as timestamps, only upper
618                  * boundary need be checked for overflow.
619                  */
620                 if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
621                         ereport(ERROR,
622                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
623                                          errmsg("date out of range for timestamp")));
624
625                 j2date(dateVal + POSTGRES_EPOCH_JDATE,
626                            &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
627                 tm->tm_hour = 0;
628                 tm->tm_min = 0;
629                 tm->tm_sec = 0;
630                 tz = DetermineTimeZoneOffset(tm, session_timezone);
631
632                 result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
633
634                 /*
635                  * Since it is possible to go beyond allowed timestamptz range because
636                  * of time zone, check for allowed timestamp range after adding tz.
637                  */
638                 if (!IS_VALID_TIMESTAMP(result))
639                         ereport(ERROR,
640                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
641                                          errmsg("date out of range for timestamp")));
642         }
643
644         return result;
645 }
646
647 /*
648  * date2timestamp_no_overflow
649  *
650  * This is chartered to produce a double value that is numerically
651  * equivalent to the corresponding Timestamp value, if the date is in the
652  * valid range of Timestamps, but in any case not throw an overflow error.
653  * We can do this since the numerical range of double is greater than
654  * that of non-erroneous timestamps.  The results are currently only
655  * used for statistical estimation purposes.
656  */
657 double
658 date2timestamp_no_overflow(DateADT dateVal)
659 {
660         double          result;
661
662         if (DATE_IS_NOBEGIN(dateVal))
663                 result = -DBL_MAX;
664         else if (DATE_IS_NOEND(dateVal))
665                 result = DBL_MAX;
666         else
667         {
668                 /* date is days since 2000, timestamp is microseconds since same... */
669                 result = dateVal * (double) USECS_PER_DAY;
670         }
671
672         return result;
673 }
674
675
676 /*
677  * Crosstype comparison functions for dates
678  */
679
680 Datum
681 date_eq_timestamp(PG_FUNCTION_ARGS)
682 {
683         DateADT         dateVal = PG_GETARG_DATEADT(0);
684         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
685         Timestamp       dt1;
686
687         dt1 = date2timestamp(dateVal);
688
689         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
690 }
691
692 Datum
693 date_ne_timestamp(PG_FUNCTION_ARGS)
694 {
695         DateADT         dateVal = PG_GETARG_DATEADT(0);
696         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
697         Timestamp       dt1;
698
699         dt1 = date2timestamp(dateVal);
700
701         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
702 }
703
704 Datum
705 date_lt_timestamp(PG_FUNCTION_ARGS)
706 {
707         DateADT         dateVal = PG_GETARG_DATEADT(0);
708         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
709         Timestamp       dt1;
710
711         dt1 = date2timestamp(dateVal);
712
713         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
714 }
715
716 Datum
717 date_gt_timestamp(PG_FUNCTION_ARGS)
718 {
719         DateADT         dateVal = PG_GETARG_DATEADT(0);
720         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
721         Timestamp       dt1;
722
723         dt1 = date2timestamp(dateVal);
724
725         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
726 }
727
728 Datum
729 date_le_timestamp(PG_FUNCTION_ARGS)
730 {
731         DateADT         dateVal = PG_GETARG_DATEADT(0);
732         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
733         Timestamp       dt1;
734
735         dt1 = date2timestamp(dateVal);
736
737         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
738 }
739
740 Datum
741 date_ge_timestamp(PG_FUNCTION_ARGS)
742 {
743         DateADT         dateVal = PG_GETARG_DATEADT(0);
744         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
745         Timestamp       dt1;
746
747         dt1 = date2timestamp(dateVal);
748
749         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
750 }
751
752 Datum
753 date_cmp_timestamp(PG_FUNCTION_ARGS)
754 {
755         DateADT         dateVal = PG_GETARG_DATEADT(0);
756         Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
757         Timestamp       dt1;
758
759         dt1 = date2timestamp(dateVal);
760
761         PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
762 }
763
764 Datum
765 date_eq_timestamptz(PG_FUNCTION_ARGS)
766 {
767         DateADT         dateVal = PG_GETARG_DATEADT(0);
768         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
769         TimestampTz dt1;
770
771         dt1 = date2timestamptz(dateVal);
772
773         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
774 }
775
776 Datum
777 date_ne_timestamptz(PG_FUNCTION_ARGS)
778 {
779         DateADT         dateVal = PG_GETARG_DATEADT(0);
780         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
781         TimestampTz dt1;
782
783         dt1 = date2timestamptz(dateVal);
784
785         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
786 }
787
788 Datum
789 date_lt_timestamptz(PG_FUNCTION_ARGS)
790 {
791         DateADT         dateVal = PG_GETARG_DATEADT(0);
792         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
793         TimestampTz dt1;
794
795         dt1 = date2timestamptz(dateVal);
796
797         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
798 }
799
800 Datum
801 date_gt_timestamptz(PG_FUNCTION_ARGS)
802 {
803         DateADT         dateVal = PG_GETARG_DATEADT(0);
804         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
805         TimestampTz dt1;
806
807         dt1 = date2timestamptz(dateVal);
808
809         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
810 }
811
812 Datum
813 date_le_timestamptz(PG_FUNCTION_ARGS)
814 {
815         DateADT         dateVal = PG_GETARG_DATEADT(0);
816         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
817         TimestampTz dt1;
818
819         dt1 = date2timestamptz(dateVal);
820
821         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
822 }
823
824 Datum
825 date_ge_timestamptz(PG_FUNCTION_ARGS)
826 {
827         DateADT         dateVal = PG_GETARG_DATEADT(0);
828         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
829         TimestampTz dt1;
830
831         dt1 = date2timestamptz(dateVal);
832
833         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
834 }
835
836 Datum
837 date_cmp_timestamptz(PG_FUNCTION_ARGS)
838 {
839         DateADT         dateVal = PG_GETARG_DATEADT(0);
840         TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
841         TimestampTz dt1;
842
843         dt1 = date2timestamptz(dateVal);
844
845         PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
846 }
847
848 Datum
849 timestamp_eq_date(PG_FUNCTION_ARGS)
850 {
851         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
852         DateADT         dateVal = PG_GETARG_DATEADT(1);
853         Timestamp       dt2;
854
855         dt2 = date2timestamp(dateVal);
856
857         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
858 }
859
860 Datum
861 timestamp_ne_date(PG_FUNCTION_ARGS)
862 {
863         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
864         DateADT         dateVal = PG_GETARG_DATEADT(1);
865         Timestamp       dt2;
866
867         dt2 = date2timestamp(dateVal);
868
869         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
870 }
871
872 Datum
873 timestamp_lt_date(PG_FUNCTION_ARGS)
874 {
875         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
876         DateADT         dateVal = PG_GETARG_DATEADT(1);
877         Timestamp       dt2;
878
879         dt2 = date2timestamp(dateVal);
880
881         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
882 }
883
884 Datum
885 timestamp_gt_date(PG_FUNCTION_ARGS)
886 {
887         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
888         DateADT         dateVal = PG_GETARG_DATEADT(1);
889         Timestamp       dt2;
890
891         dt2 = date2timestamp(dateVal);
892
893         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
894 }
895
896 Datum
897 timestamp_le_date(PG_FUNCTION_ARGS)
898 {
899         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
900         DateADT         dateVal = PG_GETARG_DATEADT(1);
901         Timestamp       dt2;
902
903         dt2 = date2timestamp(dateVal);
904
905         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
906 }
907
908 Datum
909 timestamp_ge_date(PG_FUNCTION_ARGS)
910 {
911         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
912         DateADT         dateVal = PG_GETARG_DATEADT(1);
913         Timestamp       dt2;
914
915         dt2 = date2timestamp(dateVal);
916
917         PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
918 }
919
920 Datum
921 timestamp_cmp_date(PG_FUNCTION_ARGS)
922 {
923         Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
924         DateADT         dateVal = PG_GETARG_DATEADT(1);
925         Timestamp       dt2;
926
927         dt2 = date2timestamp(dateVal);
928
929         PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
930 }
931
932 Datum
933 timestamptz_eq_date(PG_FUNCTION_ARGS)
934 {
935         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
936         DateADT         dateVal = PG_GETARG_DATEADT(1);
937         TimestampTz dt2;
938
939         dt2 = date2timestamptz(dateVal);
940
941         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
942 }
943
944 Datum
945 timestamptz_ne_date(PG_FUNCTION_ARGS)
946 {
947         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
948         DateADT         dateVal = PG_GETARG_DATEADT(1);
949         TimestampTz dt2;
950
951         dt2 = date2timestamptz(dateVal);
952
953         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
954 }
955
956 Datum
957 timestamptz_lt_date(PG_FUNCTION_ARGS)
958 {
959         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
960         DateADT         dateVal = PG_GETARG_DATEADT(1);
961         TimestampTz dt2;
962
963         dt2 = date2timestamptz(dateVal);
964
965         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
966 }
967
968 Datum
969 timestamptz_gt_date(PG_FUNCTION_ARGS)
970 {
971         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
972         DateADT         dateVal = PG_GETARG_DATEADT(1);
973         TimestampTz dt2;
974
975         dt2 = date2timestamptz(dateVal);
976
977         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
978 }
979
980 Datum
981 timestamptz_le_date(PG_FUNCTION_ARGS)
982 {
983         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
984         DateADT         dateVal = PG_GETARG_DATEADT(1);
985         TimestampTz dt2;
986
987         dt2 = date2timestamptz(dateVal);
988
989         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
990 }
991
992 Datum
993 timestamptz_ge_date(PG_FUNCTION_ARGS)
994 {
995         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
996         DateADT         dateVal = PG_GETARG_DATEADT(1);
997         TimestampTz dt2;
998
999         dt2 = date2timestamptz(dateVal);
1000
1001         PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
1002 }
1003
1004 Datum
1005 timestamptz_cmp_date(PG_FUNCTION_ARGS)
1006 {
1007         TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1008         DateADT         dateVal = PG_GETARG_DATEADT(1);
1009         TimestampTz dt2;
1010
1011         dt2 = date2timestamptz(dateVal);
1012
1013         PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
1014 }
1015
1016
1017 /* Add an interval to a date, giving a new date.
1018  * Must handle both positive and negative intervals.
1019  *
1020  * We implement this by promoting the date to timestamp (without time zone)
1021  * and then using the timestamp plus interval function.
1022  */
1023 Datum
1024 date_pl_interval(PG_FUNCTION_ARGS)
1025 {
1026         DateADT         dateVal = PG_GETARG_DATEADT(0);
1027         Interval   *span = PG_GETARG_INTERVAL_P(1);
1028         Timestamp       dateStamp;
1029
1030         dateStamp = date2timestamp(dateVal);
1031
1032         return DirectFunctionCall2(timestamp_pl_interval,
1033                                                            TimestampGetDatum(dateStamp),
1034                                                            PointerGetDatum(span));
1035 }
1036
1037 /* Subtract an interval from a date, giving a new date.
1038  * Must handle both positive and negative intervals.
1039  *
1040  * We implement this by promoting the date to timestamp (without time zone)
1041  * and then using the timestamp minus interval function.
1042  */
1043 Datum
1044 date_mi_interval(PG_FUNCTION_ARGS)
1045 {
1046         DateADT         dateVal = PG_GETARG_DATEADT(0);
1047         Interval   *span = PG_GETARG_INTERVAL_P(1);
1048         Timestamp       dateStamp;
1049
1050         dateStamp = date2timestamp(dateVal);
1051
1052         return DirectFunctionCall2(timestamp_mi_interval,
1053                                                            TimestampGetDatum(dateStamp),
1054                                                            PointerGetDatum(span));
1055 }
1056
1057 /* date_timestamp()
1058  * Convert date to timestamp data type.
1059  */
1060 Datum
1061 date_timestamp(PG_FUNCTION_ARGS)
1062 {
1063         DateADT         dateVal = PG_GETARG_DATEADT(0);
1064         Timestamp       result;
1065
1066         result = date2timestamp(dateVal);
1067
1068         PG_RETURN_TIMESTAMP(result);
1069 }
1070
1071 /* timestamp_date()
1072  * Convert timestamp to date data type.
1073  */
1074 Datum
1075 timestamp_date(PG_FUNCTION_ARGS)
1076 {
1077         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
1078         DateADT         result;
1079         struct pg_tm tt,
1080                            *tm = &tt;
1081         fsec_t          fsec;
1082
1083         if (TIMESTAMP_IS_NOBEGIN(timestamp))
1084                 DATE_NOBEGIN(result);
1085         else if (TIMESTAMP_IS_NOEND(timestamp))
1086                 DATE_NOEND(result);
1087         else
1088         {
1089                 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1090                         ereport(ERROR,
1091                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1092                                          errmsg("timestamp out of range")));
1093
1094                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1095         }
1096
1097         PG_RETURN_DATEADT(result);
1098 }
1099
1100
1101 /* date_timestamptz()
1102  * Convert date to timestamp with time zone data type.
1103  */
1104 Datum
1105 date_timestamptz(PG_FUNCTION_ARGS)
1106 {
1107         DateADT         dateVal = PG_GETARG_DATEADT(0);
1108         TimestampTz result;
1109
1110         result = date2timestamptz(dateVal);
1111
1112         PG_RETURN_TIMESTAMP(result);
1113 }
1114
1115
1116 /* timestamptz_date()
1117  * Convert timestamp with time zone to date data type.
1118  */
1119 Datum
1120 timestamptz_date(PG_FUNCTION_ARGS)
1121 {
1122         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1123         DateADT         result;
1124         struct pg_tm tt,
1125                            *tm = &tt;
1126         fsec_t          fsec;
1127         int                     tz;
1128
1129         if (TIMESTAMP_IS_NOBEGIN(timestamp))
1130                 DATE_NOBEGIN(result);
1131         else if (TIMESTAMP_IS_NOEND(timestamp))
1132                 DATE_NOEND(result);
1133         else
1134         {
1135                 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1136                         ereport(ERROR,
1137                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1138                                          errmsg("timestamp out of range")));
1139
1140                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1141         }
1142
1143         PG_RETURN_DATEADT(result);
1144 }
1145
1146
1147 /* abstime_date()
1148  * Convert abstime to date data type.
1149  */
1150 Datum
1151 abstime_date(PG_FUNCTION_ARGS)
1152 {
1153         AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
1154         DateADT         result;
1155         struct pg_tm tt,
1156                            *tm = &tt;
1157         int                     tz;
1158
1159         switch (abstime)
1160         {
1161                 case INVALID_ABSTIME:
1162                         ereport(ERROR,
1163                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1164                                    errmsg("cannot convert reserved abstime value to date")));
1165                         result = 0;                     /* keep compiler quiet */
1166                         break;
1167
1168                 case NOSTART_ABSTIME:
1169                         DATE_NOBEGIN(result);
1170                         break;
1171
1172                 case NOEND_ABSTIME:
1173                         DATE_NOEND(result);
1174                         break;
1175
1176                 default:
1177                         abstime2tm(abstime, &tz, tm, NULL);
1178                         /* Prevent overflow in Julian-day routines */
1179                         if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1180                                 ereport(ERROR,
1181                                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1182                                                  errmsg("abstime out of range for date")));
1183                         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1184                         /* Now check for just-out-of-range dates */
1185                         if (!IS_VALID_DATE(result))
1186                                 ereport(ERROR,
1187                                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1188                                                  errmsg("abstime out of range for date")));
1189                         break;
1190         }
1191
1192         PG_RETURN_DATEADT(result);
1193 }
1194
1195
1196 /*****************************************************************************
1197  *       Time ADT
1198  *****************************************************************************/
1199
1200 Datum
1201 time_in(PG_FUNCTION_ARGS)
1202 {
1203         char       *str = PG_GETARG_CSTRING(0);
1204
1205 #ifdef NOT_USED
1206         Oid                     typelem = PG_GETARG_OID(1);
1207 #endif
1208         int32           typmod = PG_GETARG_INT32(2);
1209         TimeADT         result;
1210         fsec_t          fsec;
1211         struct pg_tm tt,
1212                            *tm = &tt;
1213         int                     tz;
1214         int                     nf;
1215         int                     dterr;
1216         char            workbuf[MAXDATELEN + 1];
1217         char       *field[MAXDATEFIELDS];
1218         int                     dtype;
1219         int                     ftype[MAXDATEFIELDS];
1220
1221         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1222                                                   field, ftype, MAXDATEFIELDS, &nf);
1223         if (dterr == 0)
1224                 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
1225         if (dterr != 0)
1226                 DateTimeParseError(dterr, str, "time");
1227
1228         tm2time(tm, fsec, &result);
1229         AdjustTimeForTypmod(&result, typmod);
1230
1231         PG_RETURN_TIMEADT(result);
1232 }
1233
1234 /* tm2time()
1235  * Convert a tm structure to a time data type.
1236  */
1237 static int
1238 tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
1239 {
1240         *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
1241                            * USECS_PER_SEC) + fsec;
1242         return 0;
1243 }
1244
1245 /* time2tm()
1246  * Convert time data type to POSIX time structure.
1247  *
1248  * For dates within the range of pg_time_t, convert to the local time zone.
1249  * If out of this range, leave as UTC (in practice that could only happen
1250  * if pg_time_t is just 32 bits) - thomas 97/05/27
1251  */
1252 static int
1253 time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
1254 {
1255         tm->tm_hour = time / USECS_PER_HOUR;
1256         time -= tm->tm_hour * USECS_PER_HOUR;
1257         tm->tm_min = time / USECS_PER_MINUTE;
1258         time -= tm->tm_min * USECS_PER_MINUTE;
1259         tm->tm_sec = time / USECS_PER_SEC;
1260         time -= tm->tm_sec * USECS_PER_SEC;
1261         *fsec = time;
1262         return 0;
1263 }
1264
1265 Datum
1266 time_out(PG_FUNCTION_ARGS)
1267 {
1268         TimeADT         time = PG_GETARG_TIMEADT(0);
1269         char       *result;
1270         struct pg_tm tt,
1271                            *tm = &tt;
1272         fsec_t          fsec;
1273         char            buf[MAXDATELEN + 1];
1274
1275         time2tm(time, tm, &fsec);
1276         EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
1277
1278         result = pstrdup(buf);
1279         PG_RETURN_CSTRING(result);
1280 }
1281
1282 /*
1283  *              time_recv                       - converts external binary format to time
1284  */
1285 Datum
1286 time_recv(PG_FUNCTION_ARGS)
1287 {
1288         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
1289
1290 #ifdef NOT_USED
1291         Oid                     typelem = PG_GETARG_OID(1);
1292 #endif
1293         int32           typmod = PG_GETARG_INT32(2);
1294         TimeADT         result;
1295
1296         result = pq_getmsgint64(buf);
1297
1298         if (result < INT64CONST(0) || result > USECS_PER_DAY)
1299                 ereport(ERROR,
1300                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1301                                  errmsg("time out of range")));
1302
1303         AdjustTimeForTypmod(&result, typmod);
1304
1305         PG_RETURN_TIMEADT(result);
1306 }
1307
1308 /*
1309  *              time_send                       - converts time to binary format
1310  */
1311 Datum
1312 time_send(PG_FUNCTION_ARGS)
1313 {
1314         TimeADT         time = PG_GETARG_TIMEADT(0);
1315         StringInfoData buf;
1316
1317         pq_begintypsend(&buf);
1318         pq_sendint64(&buf, time);
1319         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1320 }
1321
1322 Datum
1323 timetypmodin(PG_FUNCTION_ARGS)
1324 {
1325         ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
1326
1327         PG_RETURN_INT32(anytime_typmodin(false, ta));
1328 }
1329
1330 Datum
1331 timetypmodout(PG_FUNCTION_ARGS)
1332 {
1333         int32           typmod = PG_GETARG_INT32(0);
1334
1335         PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1336 }
1337
1338 /*
1339  *              make_time                       - time constructor
1340  */
1341 Datum
1342 make_time(PG_FUNCTION_ARGS)
1343 {
1344         int                     tm_hour = PG_GETARG_INT32(0);
1345         int                     tm_min = PG_GETARG_INT32(1);
1346         double          sec = PG_GETARG_FLOAT8(2);
1347         TimeADT         time;
1348
1349         /* This should match the checks in DecodeTimeOnly */
1350         if (tm_hour < 0 || tm_min < 0 || tm_min > MINS_PER_HOUR - 1 ||
1351                 sec < 0 || sec > SECS_PER_MINUTE ||
1352                 tm_hour > HOURS_PER_DAY ||
1353         /* test for > 24:00:00 */
1354                 (tm_hour == HOURS_PER_DAY && (tm_min > 0 || sec > 0)))
1355                 ereport(ERROR,
1356                                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
1357                                  errmsg("time field value out of range: %d:%02d:%02g",
1358                                                 tm_hour, tm_min, sec)));
1359
1360         /* This should match tm2time */
1361         time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
1362                         * USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
1363
1364         PG_RETURN_TIMEADT(time);
1365 }
1366
1367
1368 /* time_transform()
1369  * Flatten calls to time_scale() and timetz_scale() that solely represent
1370  * increases in allowed precision.
1371  */
1372 Datum
1373 time_transform(PG_FUNCTION_ARGS)
1374 {
1375         PG_RETURN_POINTER(TemporalTransform(MAX_TIME_PRECISION,
1376                                                                                 (Node *) PG_GETARG_POINTER(0)));
1377 }
1378
1379 /* time_scale()
1380  * Adjust time type for specified scale factor.
1381  * Used by PostgreSQL type system to stuff columns.
1382  */
1383 Datum
1384 time_scale(PG_FUNCTION_ARGS)
1385 {
1386         TimeADT         time = PG_GETARG_TIMEADT(0);
1387         int32           typmod = PG_GETARG_INT32(1);
1388         TimeADT         result;
1389
1390         result = time;
1391         AdjustTimeForTypmod(&result, typmod);
1392
1393         PG_RETURN_TIMEADT(result);
1394 }
1395
1396 /* AdjustTimeForTypmod()
1397  * Force the precision of the time value to a specified value.
1398  * Uses *exactly* the same code as in AdjustTimestampForTypemod()
1399  * but we make a separate copy because those types do not
1400  * have a fundamental tie together but rather a coincidence of
1401  * implementation. - thomas
1402  */
1403 static void
1404 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1405 {
1406         static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1407                 INT64CONST(1000000),
1408                 INT64CONST(100000),
1409                 INT64CONST(10000),
1410                 INT64CONST(1000),
1411                 INT64CONST(100),
1412                 INT64CONST(10),
1413                 INT64CONST(1)
1414         };
1415
1416         static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1417                 INT64CONST(500000),
1418                 INT64CONST(50000),
1419                 INT64CONST(5000),
1420                 INT64CONST(500),
1421                 INT64CONST(50),
1422                 INT64CONST(5),
1423                 INT64CONST(0)
1424         };
1425
1426         if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1427         {
1428                 if (*time >= INT64CONST(0))
1429                         *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
1430                                 TimeScales[typmod];
1431                 else
1432                         *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
1433                                           TimeScales[typmod]);
1434         }
1435 }
1436
1437
1438 Datum
1439 time_eq(PG_FUNCTION_ARGS)
1440 {
1441         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1442         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1443
1444         PG_RETURN_BOOL(time1 == time2);
1445 }
1446
1447 Datum
1448 time_ne(PG_FUNCTION_ARGS)
1449 {
1450         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1451         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1452
1453         PG_RETURN_BOOL(time1 != time2);
1454 }
1455
1456 Datum
1457 time_lt(PG_FUNCTION_ARGS)
1458 {
1459         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1460         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1461
1462         PG_RETURN_BOOL(time1 < time2);
1463 }
1464
1465 Datum
1466 time_le(PG_FUNCTION_ARGS)
1467 {
1468         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1469         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1470
1471         PG_RETURN_BOOL(time1 <= time2);
1472 }
1473
1474 Datum
1475 time_gt(PG_FUNCTION_ARGS)
1476 {
1477         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1478         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1479
1480         PG_RETURN_BOOL(time1 > time2);
1481 }
1482
1483 Datum
1484 time_ge(PG_FUNCTION_ARGS)
1485 {
1486         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1487         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1488
1489         PG_RETURN_BOOL(time1 >= time2);
1490 }
1491
1492 Datum
1493 time_cmp(PG_FUNCTION_ARGS)
1494 {
1495         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1496         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1497
1498         if (time1 < time2)
1499                 PG_RETURN_INT32(-1);
1500         if (time1 > time2)
1501                 PG_RETURN_INT32(1);
1502         PG_RETURN_INT32(0);
1503 }
1504
1505 Datum
1506 time_hash(PG_FUNCTION_ARGS)
1507 {
1508         return hashint8(fcinfo);
1509 }
1510
1511 Datum
1512 time_larger(PG_FUNCTION_ARGS)
1513 {
1514         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1515         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1516
1517         PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1518 }
1519
1520 Datum
1521 time_smaller(PG_FUNCTION_ARGS)
1522 {
1523         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1524         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1525
1526         PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1527 }
1528
1529 /* overlaps_time() --- implements the SQL OVERLAPS operator.
1530  *
1531  * Algorithm is per SQL spec.  This is much harder than you'd think
1532  * because the spec requires us to deliver a non-null answer in some cases
1533  * where some of the inputs are null.
1534  */
1535 Datum
1536 overlaps_time(PG_FUNCTION_ARGS)
1537 {
1538         /*
1539          * The arguments are TimeADT, but we leave them as generic Datums to avoid
1540          * dereferencing nulls (TimeADT is pass-by-reference!)
1541          */
1542         Datum           ts1 = PG_GETARG_DATUM(0);
1543         Datum           te1 = PG_GETARG_DATUM(1);
1544         Datum           ts2 = PG_GETARG_DATUM(2);
1545         Datum           te2 = PG_GETARG_DATUM(3);
1546         bool            ts1IsNull = PG_ARGISNULL(0);
1547         bool            te1IsNull = PG_ARGISNULL(1);
1548         bool            ts2IsNull = PG_ARGISNULL(2);
1549         bool            te2IsNull = PG_ARGISNULL(3);
1550
1551 #define TIMEADT_GT(t1,t2) \
1552         (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1553 #define TIMEADT_LT(t1,t2) \
1554         (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1555
1556         /*
1557          * If both endpoints of interval 1 are null, the result is null (unknown).
1558          * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1559          * take ts1 as the lesser endpoint.
1560          */
1561         if (ts1IsNull)
1562         {
1563                 if (te1IsNull)
1564                         PG_RETURN_NULL();
1565                 /* swap null for non-null */
1566                 ts1 = te1;
1567                 te1IsNull = true;
1568         }
1569         else if (!te1IsNull)
1570         {
1571                 if (TIMEADT_GT(ts1, te1))
1572                 {
1573                         Datum           tt = ts1;
1574
1575                         ts1 = te1;
1576                         te1 = tt;
1577                 }
1578         }
1579
1580         /* Likewise for interval 2. */
1581         if (ts2IsNull)
1582         {
1583                 if (te2IsNull)
1584                         PG_RETURN_NULL();
1585                 /* swap null for non-null */
1586                 ts2 = te2;
1587                 te2IsNull = true;
1588         }
1589         else if (!te2IsNull)
1590         {
1591                 if (TIMEADT_GT(ts2, te2))
1592                 {
1593                         Datum           tt = ts2;
1594
1595                         ts2 = te2;
1596                         te2 = tt;
1597                 }
1598         }
1599
1600         /*
1601          * At this point neither ts1 nor ts2 is null, so we can consider three
1602          * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1603          */
1604         if (TIMEADT_GT(ts1, ts2))
1605         {
1606                 /*
1607                  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1608                  * in the presence of nulls it's not quite completely so.
1609                  */
1610                 if (te2IsNull)
1611                         PG_RETURN_NULL();
1612                 if (TIMEADT_LT(ts1, te2))
1613                         PG_RETURN_BOOL(true);
1614                 if (te1IsNull)
1615                         PG_RETURN_NULL();
1616
1617                 /*
1618                  * If te1 is not null then we had ts1 <= te1 above, and we just found
1619                  * ts1 >= te2, hence te1 >= te2.
1620                  */
1621                 PG_RETURN_BOOL(false);
1622         }
1623         else if (TIMEADT_LT(ts1, ts2))
1624         {
1625                 /* This case is ts2 < te1 OR te2 < te1 */
1626                 if (te1IsNull)
1627                         PG_RETURN_NULL();
1628                 if (TIMEADT_LT(ts2, te1))
1629                         PG_RETURN_BOOL(true);
1630                 if (te2IsNull)
1631                         PG_RETURN_NULL();
1632
1633                 /*
1634                  * If te2 is not null then we had ts2 <= te2 above, and we just found
1635                  * ts2 >= te1, hence te2 >= te1.
1636                  */
1637                 PG_RETURN_BOOL(false);
1638         }
1639         else
1640         {
1641                 /*
1642                  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1643                  * rather silly way of saying "true if both are nonnull, else null".
1644                  */
1645                 if (te1IsNull || te2IsNull)
1646                         PG_RETURN_NULL();
1647                 PG_RETURN_BOOL(true);
1648         }
1649
1650 #undef TIMEADT_GT
1651 #undef TIMEADT_LT
1652 }
1653
1654 /* timestamp_time()
1655  * Convert timestamp to time data type.
1656  */
1657 Datum
1658 timestamp_time(PG_FUNCTION_ARGS)
1659 {
1660         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
1661         TimeADT         result;
1662         struct pg_tm tt,
1663                            *tm = &tt;
1664         fsec_t          fsec;
1665
1666         if (TIMESTAMP_NOT_FINITE(timestamp))
1667                 PG_RETURN_NULL();
1668
1669         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1670                 ereport(ERROR,
1671                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1672                                  errmsg("timestamp out of range")));
1673
1674         /*
1675          * Could also do this with time = (timestamp / USECS_PER_DAY *
1676          * USECS_PER_DAY) - timestamp;
1677          */
1678         result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1679                           USECS_PER_SEC) + fsec;
1680
1681         PG_RETURN_TIMEADT(result);
1682 }
1683
1684 /* timestamptz_time()
1685  * Convert timestamptz to time data type.
1686  */
1687 Datum
1688 timestamptz_time(PG_FUNCTION_ARGS)
1689 {
1690         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1691         TimeADT         result;
1692         struct pg_tm tt,
1693                            *tm = &tt;
1694         int                     tz;
1695         fsec_t          fsec;
1696
1697         if (TIMESTAMP_NOT_FINITE(timestamp))
1698                 PG_RETURN_NULL();
1699
1700         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1701                 ereport(ERROR,
1702                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1703                                  errmsg("timestamp out of range")));
1704
1705         /*
1706          * Could also do this with time = (timestamp / USECS_PER_DAY *
1707          * USECS_PER_DAY) - timestamp;
1708          */
1709         result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1710                           USECS_PER_SEC) + fsec;
1711
1712         PG_RETURN_TIMEADT(result);
1713 }
1714
1715 /* datetime_timestamp()
1716  * Convert date and time to timestamp data type.
1717  */
1718 Datum
1719 datetime_timestamp(PG_FUNCTION_ARGS)
1720 {
1721         DateADT         date = PG_GETARG_DATEADT(0);
1722         TimeADT         time = PG_GETARG_TIMEADT(1);
1723         Timestamp       result;
1724
1725         result = date2timestamp(date);
1726         if (!TIMESTAMP_NOT_FINITE(result))
1727         {
1728                 result += time;
1729                 if (!IS_VALID_TIMESTAMP(result))
1730                         ereport(ERROR,
1731                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1732                                          errmsg("timestamp out of range")));
1733         }
1734
1735         PG_RETURN_TIMESTAMP(result);
1736 }
1737
1738 /* time_interval()
1739  * Convert time to interval data type.
1740  */
1741 Datum
1742 time_interval(PG_FUNCTION_ARGS)
1743 {
1744         TimeADT         time = PG_GETARG_TIMEADT(0);
1745         Interval   *result;
1746
1747         result = (Interval *) palloc(sizeof(Interval));
1748
1749         result->time = time;
1750         result->day = 0;
1751         result->month = 0;
1752
1753         PG_RETURN_INTERVAL_P(result);
1754 }
1755
1756 /* interval_time()
1757  * Convert interval to time data type.
1758  *
1759  * This is defined as producing the fractional-day portion of the interval.
1760  * Therefore, we can just ignore the months field.  It is not real clear
1761  * what to do with negative intervals, but we choose to subtract the floor,
1762  * so that, say, '-2 hours' becomes '22:00:00'.
1763  */
1764 Datum
1765 interval_time(PG_FUNCTION_ARGS)
1766 {
1767         Interval   *span = PG_GETARG_INTERVAL_P(0);
1768         TimeADT         result;
1769         int64           days;
1770
1771         result = span->time;
1772         if (result >= USECS_PER_DAY)
1773         {
1774                 days = result / USECS_PER_DAY;
1775                 result -= days * USECS_PER_DAY;
1776         }
1777         else if (result < 0)
1778         {
1779                 days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
1780                 result += days * USECS_PER_DAY;
1781         }
1782
1783         PG_RETURN_TIMEADT(result);
1784 }
1785
1786 /* time_mi_time()
1787  * Subtract two times to produce an interval.
1788  */
1789 Datum
1790 time_mi_time(PG_FUNCTION_ARGS)
1791 {
1792         TimeADT         time1 = PG_GETARG_TIMEADT(0);
1793         TimeADT         time2 = PG_GETARG_TIMEADT(1);
1794         Interval   *result;
1795
1796         result = (Interval *) palloc(sizeof(Interval));
1797
1798         result->month = 0;
1799         result->day = 0;
1800         result->time = time1 - time2;
1801
1802         PG_RETURN_INTERVAL_P(result);
1803 }
1804
1805 /* time_pl_interval()
1806  * Add interval to time.
1807  */
1808 Datum
1809 time_pl_interval(PG_FUNCTION_ARGS)
1810 {
1811         TimeADT         time = PG_GETARG_TIMEADT(0);
1812         Interval   *span = PG_GETARG_INTERVAL_P(1);
1813         TimeADT         result;
1814
1815         result = time + span->time;
1816         result -= result / USECS_PER_DAY * USECS_PER_DAY;
1817         if (result < INT64CONST(0))
1818                 result += USECS_PER_DAY;
1819
1820         PG_RETURN_TIMEADT(result);
1821 }
1822
1823 /* time_mi_interval()
1824  * Subtract interval from time.
1825  */
1826 Datum
1827 time_mi_interval(PG_FUNCTION_ARGS)
1828 {
1829         TimeADT         time = PG_GETARG_TIMEADT(0);
1830         Interval   *span = PG_GETARG_INTERVAL_P(1);
1831         TimeADT         result;
1832
1833         result = time - span->time;
1834         result -= result / USECS_PER_DAY * USECS_PER_DAY;
1835         if (result < INT64CONST(0))
1836                 result += USECS_PER_DAY;
1837
1838         PG_RETURN_TIMEADT(result);
1839 }
1840
1841
1842 /* time_part()
1843  * Extract specified field from time type.
1844  */
1845 Datum
1846 time_part(PG_FUNCTION_ARGS)
1847 {
1848         text       *units = PG_GETARG_TEXT_PP(0);
1849         TimeADT         time = PG_GETARG_TIMEADT(1);
1850         float8          result;
1851         int                     type,
1852                                 val;
1853         char       *lowunits;
1854
1855         lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1856                                                                                         VARSIZE_ANY_EXHDR(units),
1857                                                                                         false);
1858
1859         type = DecodeUnits(0, lowunits, &val);
1860         if (type == UNKNOWN_FIELD)
1861                 type = DecodeSpecial(0, lowunits, &val);
1862
1863         if (type == UNITS)
1864         {
1865                 fsec_t          fsec;
1866                 struct pg_tm tt,
1867                                    *tm = &tt;
1868
1869                 time2tm(time, tm, &fsec);
1870
1871                 switch (val)
1872                 {
1873                         case DTK_MICROSEC:
1874                                 result = tm->tm_sec * 1000000.0 + fsec;
1875                                 break;
1876
1877                         case DTK_MILLISEC:
1878                                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
1879                                 break;
1880
1881                         case DTK_SECOND:
1882                                 result = tm->tm_sec + fsec / 1000000.0;
1883                                 break;
1884
1885                         case DTK_MINUTE:
1886                                 result = tm->tm_min;
1887                                 break;
1888
1889                         case DTK_HOUR:
1890                                 result = tm->tm_hour;
1891                                 break;
1892
1893                         case DTK_TZ:
1894                         case DTK_TZ_MINUTE:
1895                         case DTK_TZ_HOUR:
1896                         case DTK_DAY:
1897                         case DTK_MONTH:
1898                         case DTK_QUARTER:
1899                         case DTK_YEAR:
1900                         case DTK_DECADE:
1901                         case DTK_CENTURY:
1902                         case DTK_MILLENNIUM:
1903                         case DTK_ISOYEAR:
1904                         default:
1905                                 ereport(ERROR,
1906                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1907                                                  errmsg("\"time\" units \"%s\" not recognized",
1908                                                                 lowunits)));
1909                                 result = 0;
1910                 }
1911         }
1912         else if (type == RESERV && val == DTK_EPOCH)
1913         {
1914                 result = time / 1000000.0;
1915         }
1916         else
1917         {
1918                 ereport(ERROR,
1919                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1920                                  errmsg("\"time\" units \"%s\" not recognized",
1921                                                 lowunits)));
1922                 result = 0;
1923         }
1924
1925         PG_RETURN_FLOAT8(result);
1926 }
1927
1928
1929 /*****************************************************************************
1930  *       Time With Time Zone ADT
1931  *****************************************************************************/
1932
1933 /* tm2timetz()
1934  * Convert a tm structure to a time data type.
1935  */
1936 static int
1937 tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
1938 {
1939         result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1940                                         USECS_PER_SEC) + fsec;
1941         result->zone = tz;
1942
1943         return 0;
1944 }
1945
1946 Datum
1947 timetz_in(PG_FUNCTION_ARGS)
1948 {
1949         char       *str = PG_GETARG_CSTRING(0);
1950
1951 #ifdef NOT_USED
1952         Oid                     typelem = PG_GETARG_OID(1);
1953 #endif
1954         int32           typmod = PG_GETARG_INT32(2);
1955         TimeTzADT  *result;
1956         fsec_t          fsec;
1957         struct pg_tm tt,
1958                            *tm = &tt;
1959         int                     tz;
1960         int                     nf;
1961         int                     dterr;
1962         char            workbuf[MAXDATELEN + 1];
1963         char       *field[MAXDATEFIELDS];
1964         int                     dtype;
1965         int                     ftype[MAXDATEFIELDS];
1966
1967         dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1968                                                   field, ftype, MAXDATEFIELDS, &nf);
1969         if (dterr == 0)
1970                 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
1971         if (dterr != 0)
1972                 DateTimeParseError(dterr, str, "time with time zone");
1973
1974         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1975         tm2timetz(tm, fsec, tz, result);
1976         AdjustTimeForTypmod(&(result->time), typmod);
1977
1978         PG_RETURN_TIMETZADT_P(result);
1979 }
1980
1981 Datum
1982 timetz_out(PG_FUNCTION_ARGS)
1983 {
1984         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
1985         char       *result;
1986         struct pg_tm tt,
1987                            *tm = &tt;
1988         fsec_t          fsec;
1989         int                     tz;
1990         char            buf[MAXDATELEN + 1];
1991
1992         timetz2tm(time, tm, &fsec, &tz);
1993         EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
1994
1995         result = pstrdup(buf);
1996         PG_RETURN_CSTRING(result);
1997 }
1998
1999 /*
2000  *              timetz_recv                     - converts external binary format to timetz
2001  */
2002 Datum
2003 timetz_recv(PG_FUNCTION_ARGS)
2004 {
2005         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
2006
2007 #ifdef NOT_USED
2008         Oid                     typelem = PG_GETARG_OID(1);
2009 #endif
2010         int32           typmod = PG_GETARG_INT32(2);
2011         TimeTzADT  *result;
2012
2013         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2014
2015         result->time = pq_getmsgint64(buf);
2016
2017         if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
2018                 ereport(ERROR,
2019                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2020                                  errmsg("time out of range")));
2021
2022         result->zone = pq_getmsgint(buf, sizeof(result->zone));
2023
2024         /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
2025         if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
2026                 ereport(ERROR,
2027                                 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
2028                                  errmsg("time zone displacement out of range")));
2029
2030         AdjustTimeForTypmod(&(result->time), typmod);
2031
2032         PG_RETURN_TIMETZADT_P(result);
2033 }
2034
2035 /*
2036  *              timetz_send                     - converts timetz to binary format
2037  */
2038 Datum
2039 timetz_send(PG_FUNCTION_ARGS)
2040 {
2041         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2042         StringInfoData buf;
2043
2044         pq_begintypsend(&buf);
2045         pq_sendint64(&buf, time->time);
2046         pq_sendint(&buf, time->zone, sizeof(time->zone));
2047         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2048 }
2049
2050 Datum
2051 timetztypmodin(PG_FUNCTION_ARGS)
2052 {
2053         ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
2054
2055         PG_RETURN_INT32(anytime_typmodin(true, ta));
2056 }
2057
2058 Datum
2059 timetztypmodout(PG_FUNCTION_ARGS)
2060 {
2061         int32           typmod = PG_GETARG_INT32(0);
2062
2063         PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
2064 }
2065
2066
2067 /* timetz2tm()
2068  * Convert TIME WITH TIME ZONE data type to POSIX time structure.
2069  */
2070 static int
2071 timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp)
2072 {
2073         TimeOffset      trem = time->time;
2074
2075         tm->tm_hour = trem / USECS_PER_HOUR;
2076         trem -= tm->tm_hour * USECS_PER_HOUR;
2077         tm->tm_min = trem / USECS_PER_MINUTE;
2078         trem -= tm->tm_min * USECS_PER_MINUTE;
2079         tm->tm_sec = trem / USECS_PER_SEC;
2080         *fsec = trem - tm->tm_sec * USECS_PER_SEC;
2081
2082         if (tzp != NULL)
2083                 *tzp = time->zone;
2084
2085         return 0;
2086 }
2087
2088 /* timetz_scale()
2089  * Adjust time type for specified scale factor.
2090  * Used by PostgreSQL type system to stuff columns.
2091  */
2092 Datum
2093 timetz_scale(PG_FUNCTION_ARGS)
2094 {
2095         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2096         int32           typmod = PG_GETARG_INT32(1);
2097         TimeTzADT  *result;
2098
2099         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2100
2101         result->time = time->time;
2102         result->zone = time->zone;
2103
2104         AdjustTimeForTypmod(&(result->time), typmod);
2105
2106         PG_RETURN_TIMETZADT_P(result);
2107 }
2108
2109
2110 static int
2111 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
2112 {
2113         TimeOffset      t1,
2114                                 t2;
2115
2116         /* Primary sort is by true (GMT-equivalent) time */
2117         t1 = time1->time + (time1->zone * USECS_PER_SEC);
2118         t2 = time2->time + (time2->zone * USECS_PER_SEC);
2119
2120         if (t1 > t2)
2121                 return 1;
2122         if (t1 < t2)
2123                 return -1;
2124
2125         /*
2126          * If same GMT time, sort by timezone; we only want to say that two
2127          * timetz's are equal if both the time and zone parts are equal.
2128          */
2129         if (time1->zone > time2->zone)
2130                 return 1;
2131         if (time1->zone < time2->zone)
2132                 return -1;
2133
2134         return 0;
2135 }
2136
2137 Datum
2138 timetz_eq(PG_FUNCTION_ARGS)
2139 {
2140         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2141         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2142
2143         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2144 }
2145
2146 Datum
2147 timetz_ne(PG_FUNCTION_ARGS)
2148 {
2149         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2150         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2151
2152         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2153 }
2154
2155 Datum
2156 timetz_lt(PG_FUNCTION_ARGS)
2157 {
2158         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2159         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2160
2161         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2162 }
2163
2164 Datum
2165 timetz_le(PG_FUNCTION_ARGS)
2166 {
2167         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2168         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2169
2170         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2171 }
2172
2173 Datum
2174 timetz_gt(PG_FUNCTION_ARGS)
2175 {
2176         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2177         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2178
2179         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2180 }
2181
2182 Datum
2183 timetz_ge(PG_FUNCTION_ARGS)
2184 {
2185         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2186         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2187
2188         PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2189 }
2190
2191 Datum
2192 timetz_cmp(PG_FUNCTION_ARGS)
2193 {
2194         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2195         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2196
2197         PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2198 }
2199
2200 Datum
2201 timetz_hash(PG_FUNCTION_ARGS)
2202 {
2203         TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
2204         uint32          thash;
2205
2206         /*
2207          * To avoid any problems with padding bytes in the struct, we figure the
2208          * field hashes separately and XOR them.
2209          */
2210         thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2211                                                                                            Int64GetDatumFast(key->time)));
2212         thash ^= DatumGetUInt32(hash_uint32(key->zone));
2213         PG_RETURN_UINT32(thash);
2214 }
2215
2216 Datum
2217 timetz_larger(PG_FUNCTION_ARGS)
2218 {
2219         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2220         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2221         TimeTzADT  *result;
2222
2223         if (timetz_cmp_internal(time1, time2) > 0)
2224                 result = time1;
2225         else
2226                 result = time2;
2227         PG_RETURN_TIMETZADT_P(result);
2228 }
2229
2230 Datum
2231 timetz_smaller(PG_FUNCTION_ARGS)
2232 {
2233         TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2234         TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2235         TimeTzADT  *result;
2236
2237         if (timetz_cmp_internal(time1, time2) < 0)
2238                 result = time1;
2239         else
2240                 result = time2;
2241         PG_RETURN_TIMETZADT_P(result);
2242 }
2243
2244 /* timetz_pl_interval()
2245  * Add interval to timetz.
2246  */
2247 Datum
2248 timetz_pl_interval(PG_FUNCTION_ARGS)
2249 {
2250         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2251         Interval   *span = PG_GETARG_INTERVAL_P(1);
2252         TimeTzADT  *result;
2253
2254         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2255
2256         result->time = time->time + span->time;
2257         result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2258         if (result->time < INT64CONST(0))
2259                 result->time += USECS_PER_DAY;
2260
2261         result->zone = time->zone;
2262
2263         PG_RETURN_TIMETZADT_P(result);
2264 }
2265
2266 /* timetz_mi_interval()
2267  * Subtract interval from timetz.
2268  */
2269 Datum
2270 timetz_mi_interval(PG_FUNCTION_ARGS)
2271 {
2272         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2273         Interval   *span = PG_GETARG_INTERVAL_P(1);
2274         TimeTzADT  *result;
2275
2276         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2277
2278         result->time = time->time - span->time;
2279         result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2280         if (result->time < INT64CONST(0))
2281                 result->time += USECS_PER_DAY;
2282
2283         result->zone = time->zone;
2284
2285         PG_RETURN_TIMETZADT_P(result);
2286 }
2287
2288 /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
2289  *
2290  * Algorithm is per SQL spec.  This is much harder than you'd think
2291  * because the spec requires us to deliver a non-null answer in some cases
2292  * where some of the inputs are null.
2293  */
2294 Datum
2295 overlaps_timetz(PG_FUNCTION_ARGS)
2296 {
2297         /*
2298          * The arguments are TimeTzADT *, but we leave them as generic Datums for
2299          * convenience of notation --- and to avoid dereferencing nulls.
2300          */
2301         Datum           ts1 = PG_GETARG_DATUM(0);
2302         Datum           te1 = PG_GETARG_DATUM(1);
2303         Datum           ts2 = PG_GETARG_DATUM(2);
2304         Datum           te2 = PG_GETARG_DATUM(3);
2305         bool            ts1IsNull = PG_ARGISNULL(0);
2306         bool            te1IsNull = PG_ARGISNULL(1);
2307         bool            ts2IsNull = PG_ARGISNULL(2);
2308         bool            te2IsNull = PG_ARGISNULL(3);
2309
2310 #define TIMETZ_GT(t1,t2) \
2311         DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2312 #define TIMETZ_LT(t1,t2) \
2313         DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2314
2315         /*
2316          * If both endpoints of interval 1 are null, the result is null (unknown).
2317          * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2318          * take ts1 as the lesser endpoint.
2319          */
2320         if (ts1IsNull)
2321         {
2322                 if (te1IsNull)
2323                         PG_RETURN_NULL();
2324                 /* swap null for non-null */
2325                 ts1 = te1;
2326                 te1IsNull = true;
2327         }
2328         else if (!te1IsNull)
2329         {
2330                 if (TIMETZ_GT(ts1, te1))
2331                 {
2332                         Datum           tt = ts1;
2333
2334                         ts1 = te1;
2335                         te1 = tt;
2336                 }
2337         }
2338
2339         /* Likewise for interval 2. */
2340         if (ts2IsNull)
2341         {
2342                 if (te2IsNull)
2343                         PG_RETURN_NULL();
2344                 /* swap null for non-null */
2345                 ts2 = te2;
2346                 te2IsNull = true;
2347         }
2348         else if (!te2IsNull)
2349         {
2350                 if (TIMETZ_GT(ts2, te2))
2351                 {
2352                         Datum           tt = ts2;
2353
2354                         ts2 = te2;
2355                         te2 = tt;
2356                 }
2357         }
2358
2359         /*
2360          * At this point neither ts1 nor ts2 is null, so we can consider three
2361          * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2362          */
2363         if (TIMETZ_GT(ts1, ts2))
2364         {
2365                 /*
2366                  * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2367                  * in the presence of nulls it's not quite completely so.
2368                  */
2369                 if (te2IsNull)
2370                         PG_RETURN_NULL();
2371                 if (TIMETZ_LT(ts1, te2))
2372                         PG_RETURN_BOOL(true);
2373                 if (te1IsNull)
2374                         PG_RETURN_NULL();
2375
2376                 /*
2377                  * If te1 is not null then we had ts1 <= te1 above, and we just found
2378                  * ts1 >= te2, hence te1 >= te2.
2379                  */
2380                 PG_RETURN_BOOL(false);
2381         }
2382         else if (TIMETZ_LT(ts1, ts2))
2383         {
2384                 /* This case is ts2 < te1 OR te2 < te1 */
2385                 if (te1IsNull)
2386                         PG_RETURN_NULL();
2387                 if (TIMETZ_LT(ts2, te1))
2388                         PG_RETURN_BOOL(true);
2389                 if (te2IsNull)
2390                         PG_RETURN_NULL();
2391
2392                 /*
2393                  * If te2 is not null then we had ts2 <= te2 above, and we just found
2394                  * ts2 >= te1, hence te2 >= te1.
2395                  */
2396                 PG_RETURN_BOOL(false);
2397         }
2398         else
2399         {
2400                 /*
2401                  * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2402                  * rather silly way of saying "true if both are nonnull, else null".
2403                  */
2404                 if (te1IsNull || te2IsNull)
2405                         PG_RETURN_NULL();
2406                 PG_RETURN_BOOL(true);
2407         }
2408
2409 #undef TIMETZ_GT
2410 #undef TIMETZ_LT
2411 }
2412
2413
2414 Datum
2415 timetz_time(PG_FUNCTION_ARGS)
2416 {
2417         TimeTzADT  *timetz = PG_GETARG_TIMETZADT_P(0);
2418         TimeADT         result;
2419
2420         /* swallow the time zone and just return the time */
2421         result = timetz->time;
2422
2423         PG_RETURN_TIMEADT(result);
2424 }
2425
2426
2427 Datum
2428 time_timetz(PG_FUNCTION_ARGS)
2429 {
2430         TimeADT         time = PG_GETARG_TIMEADT(0);
2431         TimeTzADT  *result;
2432         struct pg_tm tt,
2433                            *tm = &tt;
2434         fsec_t          fsec;
2435         int                     tz;
2436
2437         GetCurrentDateTime(tm);
2438         time2tm(time, tm, &fsec);
2439         tz = DetermineTimeZoneOffset(tm, session_timezone);
2440
2441         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2442
2443         result->time = time;
2444         result->zone = tz;
2445
2446         PG_RETURN_TIMETZADT_P(result);
2447 }
2448
2449
2450 /* timestamptz_timetz()
2451  * Convert timestamp to timetz data type.
2452  */
2453 Datum
2454 timestamptz_timetz(PG_FUNCTION_ARGS)
2455 {
2456         TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2457         TimeTzADT  *result;
2458         struct pg_tm tt,
2459                            *tm = &tt;
2460         int                     tz;
2461         fsec_t          fsec;
2462
2463         if (TIMESTAMP_NOT_FINITE(timestamp))
2464                 PG_RETURN_NULL();
2465
2466         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2467                 ereport(ERROR,
2468                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2469                                  errmsg("timestamp out of range")));
2470
2471         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2472
2473         tm2timetz(tm, fsec, tz, result);
2474
2475         PG_RETURN_TIMETZADT_P(result);
2476 }
2477
2478
2479 /* datetimetz_timestamptz()
2480  * Convert date and timetz to timestamp with time zone data type.
2481  * Timestamp is stored in GMT, so add the time zone
2482  * stored with the timetz to the result.
2483  * - thomas 2000-03-10
2484  */
2485 Datum
2486 datetimetz_timestamptz(PG_FUNCTION_ARGS)
2487 {
2488         DateADT         date = PG_GETARG_DATEADT(0);
2489         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2490         TimestampTz result;
2491
2492         if (DATE_IS_NOBEGIN(date))
2493                 TIMESTAMP_NOBEGIN(result);
2494         else if (DATE_IS_NOEND(date))
2495                 TIMESTAMP_NOEND(result);
2496         else
2497         {
2498                 /*
2499                  * Date's range is wider than timestamp's, so check for boundaries.
2500                  * Since dates have the same minimum values as timestamps, only upper
2501                  * boundary need be checked for overflow.
2502                  */
2503                 if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
2504                         ereport(ERROR,
2505                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2506                                          errmsg("date out of range for timestamp")));
2507                 result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
2508
2509                 /*
2510                  * Since it is possible to go beyond allowed timestamptz range because
2511                  * of time zone, check for allowed timestamp range after adding tz.
2512                  */
2513                 if (!IS_VALID_TIMESTAMP(result))
2514                         ereport(ERROR,
2515                                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2516                                          errmsg("date out of range for timestamp")));
2517         }
2518
2519         PG_RETURN_TIMESTAMP(result);
2520 }
2521
2522
2523 /* timetz_part()
2524  * Extract specified field from time type.
2525  */
2526 Datum
2527 timetz_part(PG_FUNCTION_ARGS)
2528 {
2529         text       *units = PG_GETARG_TEXT_PP(0);
2530         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2531         float8          result;
2532         int                     type,
2533                                 val;
2534         char       *lowunits;
2535
2536         lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2537                                                                                         VARSIZE_ANY_EXHDR(units),
2538                                                                                         false);
2539
2540         type = DecodeUnits(0, lowunits, &val);
2541         if (type == UNKNOWN_FIELD)
2542                 type = DecodeSpecial(0, lowunits, &val);
2543
2544         if (type == UNITS)
2545         {
2546                 double          dummy;
2547                 int                     tz;
2548                 fsec_t          fsec;
2549                 struct pg_tm tt,
2550                                    *tm = &tt;
2551
2552                 timetz2tm(time, tm, &fsec, &tz);
2553
2554                 switch (val)
2555                 {
2556                         case DTK_TZ:
2557                                 result = -tz;
2558                                 break;
2559
2560                         case DTK_TZ_MINUTE:
2561                                 result = -tz;
2562                                 result /= SECS_PER_MINUTE;
2563                                 FMODULO(result, dummy, (double) SECS_PER_MINUTE);
2564                                 break;
2565
2566                         case DTK_TZ_HOUR:
2567                                 dummy = -tz;
2568                                 FMODULO(dummy, result, (double) SECS_PER_HOUR);
2569                                 break;
2570
2571                         case DTK_MICROSEC:
2572                                 result = tm->tm_sec * 1000000.0 + fsec;
2573                                 break;
2574
2575                         case DTK_MILLISEC:
2576                                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
2577                                 break;
2578
2579                         case DTK_SECOND:
2580                                 result = tm->tm_sec + fsec / 1000000.0;
2581                                 break;
2582
2583                         case DTK_MINUTE:
2584                                 result = tm->tm_min;
2585                                 break;
2586
2587                         case DTK_HOUR:
2588                                 result = tm->tm_hour;
2589                                 break;
2590
2591                         case DTK_DAY:
2592                         case DTK_MONTH:
2593                         case DTK_QUARTER:
2594                         case DTK_YEAR:
2595                         case DTK_DECADE:
2596                         case DTK_CENTURY:
2597                         case DTK_MILLENNIUM:
2598                         default:
2599                                 ereport(ERROR,
2600                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2601                                 errmsg("\"time with time zone\" units \"%s\" not recognized",
2602                                            lowunits)));
2603                                 result = 0;
2604                 }
2605         }
2606         else if (type == RESERV && val == DTK_EPOCH)
2607         {
2608                 result = time->time / 1000000.0 + time->zone;
2609         }
2610         else
2611         {
2612                 ereport(ERROR,
2613                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2614                                  errmsg("\"time with time zone\" units \"%s\" not recognized",
2615                                                 lowunits)));
2616                 result = 0;
2617         }
2618
2619         PG_RETURN_FLOAT8(result);
2620 }
2621
2622 /* timetz_zone()
2623  * Encode time with time zone type with specified time zone.
2624  * Applies DST rules as of the current date.
2625  */
2626 Datum
2627 timetz_zone(PG_FUNCTION_ARGS)
2628 {
2629         text       *zone = PG_GETARG_TEXT_PP(0);
2630         TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
2631         TimeTzADT  *result;
2632         int                     tz;
2633         char            tzname[TZ_STRLEN_MAX + 1];
2634         char       *lowzone;
2635         int                     type,
2636                                 val;
2637         pg_tz      *tzp;
2638
2639         /*
2640          * Look up the requested timezone.  First we look in the timezone
2641          * abbreviation table (to handle cases like "EST"), and if that fails, we
2642          * look in the timezone database (to handle cases like
2643          * "America/New_York").  (This matches the order in which timestamp input
2644          * checks the cases; it's important because the timezone database unwisely
2645          * uses a few zone names that are identical to offset abbreviations.)
2646          */
2647         text_to_cstring_buffer(zone, tzname, sizeof(tzname));
2648
2649         /* DecodeTimezoneAbbrev requires lowercase input */
2650         lowzone = downcase_truncate_identifier(tzname,
2651                                                                                    strlen(tzname),
2652                                                                                    false);
2653
2654         type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
2655
2656         if (type == TZ || type == DTZ)
2657         {
2658                 /* fixed-offset abbreviation */
2659                 tz = -val;
2660         }
2661         else if (type == DYNTZ)
2662         {
2663                 /* dynamic-offset abbreviation, resolve using current time */
2664                 pg_time_t       now = (pg_time_t) time(NULL);
2665                 struct pg_tm *tm;
2666
2667                 tm = pg_localtime(&now, tzp);
2668                 tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
2669         }
2670         else
2671         {
2672                 /* try it as a full zone name */
2673                 tzp = pg_tzset(tzname);
2674                 if (tzp)
2675                 {
2676                         /* Get the offset-from-GMT that is valid today for the zone */
2677                         pg_time_t       now = (pg_time_t) time(NULL);
2678                         struct pg_tm *tm;
2679
2680                         tm = pg_localtime(&now, tzp);
2681                         tz = -tm->tm_gmtoff;
2682                 }
2683                 else
2684                 {
2685                         ereport(ERROR,
2686                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2687                                          errmsg("time zone \"%s\" not recognized", tzname)));
2688                         tz = 0;                         /* keep compiler quiet */
2689                 }
2690         }
2691
2692         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2693
2694         result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
2695         while (result->time < INT64CONST(0))
2696                 result->time += USECS_PER_DAY;
2697         while (result->time >= USECS_PER_DAY)
2698                 result->time -= USECS_PER_DAY;
2699
2700         result->zone = tz;
2701
2702         PG_RETURN_TIMETZADT_P(result);
2703 }
2704
2705 /* timetz_izone()
2706  * Encode time with time zone type with specified time interval as time zone.
2707  */
2708 Datum
2709 timetz_izone(PG_FUNCTION_ARGS)
2710 {
2711         Interval   *zone = PG_GETARG_INTERVAL_P(0);
2712         TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
2713         TimeTzADT  *result;
2714         int                     tz;
2715
2716         if (zone->month != 0 || zone->day != 0)
2717                 ereport(ERROR,
2718                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2719                   errmsg("interval time zone \"%s\" must not include months or days",
2720                                  DatumGetCString(DirectFunctionCall1(interval_out,
2721                                                                                                   PointerGetDatum(zone))))));
2722
2723         tz = -(zone->time / USECS_PER_SEC);
2724
2725         result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2726
2727         result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
2728         while (result->time < INT64CONST(0))
2729                 result->time += USECS_PER_DAY;
2730         while (result->time >= USECS_PER_DAY)
2731                 result->time -= USECS_PER_DAY;
2732
2733         result->zone = tz;
2734
2735         PG_RETURN_TIMETZADT_P(result);
2736 }