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