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