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