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