Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / utils / adt / date.c
bloba280ef3106e01a4b4d5bf8d1dbdc5f49d2ed3113
1 /*-------------------------------------------------------------------------
3 * date.c
4 * implements DATE and TIME data types specified in SQL-92 standard
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <ctype.h>
19 #include <limits.h>
20 #include <float.h>
21 #include <time.h>
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"
33 * gcc's -ffast-math switch breaks routines that expect exact results from
34 * expressions like timeval / SECS_PER_HOUR, where timeval is double.
36 #ifdef __FAST_MATH__
37 #error -ffast-math is known to break this code
38 #endif
41 static void EncodeSpecialDate(DateADT dt, char *str);
42 static int time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
43 static int timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
44 static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
45 static int tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
46 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
49 /* common code for timetypmodin and timetztypmodin */
50 static int32
51 anytime_typmodin(bool istz, ArrayType *ta)
53 int32 typmod;
54 int32 *tl;
55 int n;
57 tl = ArrayGetIntegerTypmods(ta, &n);
60 * we're not too tense about good error message here because grammar
61 * shouldn't allow wrong number of modifiers for TIME
63 if (n != 1)
64 ereport(ERROR,
65 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
66 errmsg("invalid type modifier")));
68 if (*tl < 0)
69 ereport(ERROR,
70 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
71 errmsg("TIME(%d)%s precision must not be negative",
72 *tl, (istz ? " WITH TIME ZONE" : ""))));
73 if (*tl > MAX_TIME_PRECISION)
75 ereport(WARNING,
76 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
77 errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
78 *tl, (istz ? " WITH TIME ZONE" : ""),
79 MAX_TIME_PRECISION)));
80 typmod = MAX_TIME_PRECISION;
82 else
83 typmod = *tl;
85 return typmod;
88 /* common code for timetypmodout and timetztypmodout */
89 static char *
90 anytime_typmodout(bool istz, int32 typmod)
92 char *res = (char *) palloc(64);
93 const char *tz = istz ? " with time zone" : " without time zone";
95 if (typmod >= 0)
96 snprintf(res, 64, "(%d)%s", (int) typmod, tz);
97 else
98 snprintf(res, 64, "%s", tz);
99 return res;
103 /*****************************************************************************
104 * Date ADT
105 *****************************************************************************/
108 /* date_in()
109 * Given date text string, convert to internal date format.
111 Datum
112 date_in(PG_FUNCTION_ARGS)
114 char *str = PG_GETARG_CSTRING(0);
115 DateADT date;
116 fsec_t fsec;
117 struct pg_tm tt,
118 *tm = &tt;
119 int tzp;
120 int dtype;
121 int nf;
122 int dterr;
123 char *field[MAXDATEFIELDS];
124 int ftype[MAXDATEFIELDS];
125 char workbuf[MAXDATELEN + 1];
127 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
128 field, ftype, MAXDATEFIELDS, &nf);
129 if (dterr == 0)
130 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
131 if (dterr != 0)
132 DateTimeParseError(dterr, str, "date");
134 switch (dtype)
136 case DTK_DATE:
137 break;
139 case DTK_CURRENT:
140 ereport(ERROR,
141 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
142 errmsg("date/time value \"current\" is no longer supported")));
144 GetCurrentDateTime(tm);
145 break;
147 case DTK_EPOCH:
148 GetEpochTime(tm);
149 break;
151 case DTK_LATE:
152 DATE_NOEND(date);
153 PG_RETURN_DATEADT(date);
155 case DTK_EARLY:
156 DATE_NOBEGIN(date);
157 PG_RETURN_DATEADT(date);
159 default:
160 DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
161 break;
164 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
165 ereport(ERROR,
166 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
167 errmsg("date out of range: \"%s\"", str)));
169 date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
171 PG_RETURN_DATEADT(date);
174 /* date_out()
175 * Given internal format date, convert to text string.
177 Datum
178 date_out(PG_FUNCTION_ARGS)
180 DateADT date = PG_GETARG_DATEADT(0);
181 char *result;
182 struct pg_tm tt,
183 *tm = &tt;
184 char buf[MAXDATELEN + 1];
186 if (DATE_NOT_FINITE(date))
187 EncodeSpecialDate(date, buf);
188 else
190 j2date(date + POSTGRES_EPOCH_JDATE,
191 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
192 EncodeDateOnly(tm, DateStyle, buf);
195 result = pstrdup(buf);
196 PG_RETURN_CSTRING(result);
200 * date_recv - converts external binary format to date
202 Datum
203 date_recv(PG_FUNCTION_ARGS)
205 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
207 PG_RETURN_DATEADT((DateADT) pq_getmsgint(buf, sizeof(DateADT)));
211 * date_send - converts date to binary format
213 Datum
214 date_send(PG_FUNCTION_ARGS)
216 DateADT date = PG_GETARG_DATEADT(0);
217 StringInfoData buf;
219 pq_begintypsend(&buf);
220 pq_sendint(&buf, date, sizeof(date));
221 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
225 * Convert reserved date values to string.
227 static void
228 EncodeSpecialDate(DateADT dt, char *str)
230 if (DATE_IS_NOBEGIN(dt))
231 strcpy(str, EARLY);
232 else if (DATE_IS_NOEND(dt))
233 strcpy(str, LATE);
234 else /* shouldn't happen */
235 elog(ERROR, "invalid argument for EncodeSpecialDate");
240 * Comparison functions for dates
243 Datum
244 date_eq(PG_FUNCTION_ARGS)
246 DateADT dateVal1 = PG_GETARG_DATEADT(0);
247 DateADT dateVal2 = PG_GETARG_DATEADT(1);
249 PG_RETURN_BOOL(dateVal1 == dateVal2);
252 Datum
253 date_ne(PG_FUNCTION_ARGS)
255 DateADT dateVal1 = PG_GETARG_DATEADT(0);
256 DateADT dateVal2 = PG_GETARG_DATEADT(1);
258 PG_RETURN_BOOL(dateVal1 != dateVal2);
261 Datum
262 date_lt(PG_FUNCTION_ARGS)
264 DateADT dateVal1 = PG_GETARG_DATEADT(0);
265 DateADT dateVal2 = PG_GETARG_DATEADT(1);
267 PG_RETURN_BOOL(dateVal1 < dateVal2);
270 Datum
271 date_le(PG_FUNCTION_ARGS)
273 DateADT dateVal1 = PG_GETARG_DATEADT(0);
274 DateADT dateVal2 = PG_GETARG_DATEADT(1);
276 PG_RETURN_BOOL(dateVal1 <= dateVal2);
279 Datum
280 date_gt(PG_FUNCTION_ARGS)
282 DateADT dateVal1 = PG_GETARG_DATEADT(0);
283 DateADT dateVal2 = PG_GETARG_DATEADT(1);
285 PG_RETURN_BOOL(dateVal1 > dateVal2);
288 Datum
289 date_ge(PG_FUNCTION_ARGS)
291 DateADT dateVal1 = PG_GETARG_DATEADT(0);
292 DateADT dateVal2 = PG_GETARG_DATEADT(1);
294 PG_RETURN_BOOL(dateVal1 >= dateVal2);
297 Datum
298 date_cmp(PG_FUNCTION_ARGS)
300 DateADT dateVal1 = PG_GETARG_DATEADT(0);
301 DateADT dateVal2 = PG_GETARG_DATEADT(1);
303 if (dateVal1 < dateVal2)
304 PG_RETURN_INT32(-1);
305 else if (dateVal1 > dateVal2)
306 PG_RETURN_INT32(1);
307 PG_RETURN_INT32(0);
310 Datum
311 date_finite(PG_FUNCTION_ARGS)
313 DateADT date = PG_GETARG_DATEADT(0);
315 PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
318 Datum
319 date_larger(PG_FUNCTION_ARGS)
321 DateADT dateVal1 = PG_GETARG_DATEADT(0);
322 DateADT dateVal2 = PG_GETARG_DATEADT(1);
324 PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
327 Datum
328 date_smaller(PG_FUNCTION_ARGS)
330 DateADT dateVal1 = PG_GETARG_DATEADT(0);
331 DateADT dateVal2 = PG_GETARG_DATEADT(1);
333 PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
336 /* Compute difference between two dates in days.
338 Datum
339 date_mi(PG_FUNCTION_ARGS)
341 DateADT dateVal1 = PG_GETARG_DATEADT(0);
342 DateADT dateVal2 = PG_GETARG_DATEADT(1);
344 if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
345 ereport(ERROR,
346 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
347 errmsg("cannot subtract infinite dates")));
349 PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
352 /* Add a number of days to a date, giving a new date.
353 * Must handle both positive and negative numbers of days.
355 Datum
356 date_pli(PG_FUNCTION_ARGS)
358 DateADT dateVal = PG_GETARG_DATEADT(0);
359 int32 days = PG_GETARG_INT32(1);
361 if (DATE_NOT_FINITE(dateVal))
362 days = 0; /* can't change infinity */
364 PG_RETURN_DATEADT(dateVal + days);
367 /* Subtract a number of days from a date, giving a new date.
369 Datum
370 date_mii(PG_FUNCTION_ARGS)
372 DateADT dateVal = PG_GETARG_DATEADT(0);
373 int32 days = PG_GETARG_INT32(1);
375 if (DATE_NOT_FINITE(dateVal))
376 days = 0; /* can't change infinity */
378 PG_RETURN_DATEADT(dateVal - days);
382 * Internal routines for promoting date to timestamp and timestamp with
383 * time zone
386 static Timestamp
387 date2timestamp(DateADT dateVal)
389 Timestamp result;
391 if (DATE_IS_NOBEGIN(dateVal))
392 TIMESTAMP_NOBEGIN(result);
393 else if (DATE_IS_NOEND(dateVal))
394 TIMESTAMP_NOEND(result);
395 else
397 #ifdef HAVE_INT64_TIMESTAMP
398 /* date is days since 2000, timestamp is microseconds since same... */
399 result = dateVal * USECS_PER_DAY;
400 /* Date's range is wider than timestamp's, so check for overflow */
401 if (result / USECS_PER_DAY != dateVal)
402 ereport(ERROR,
403 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
404 errmsg("date out of range for timestamp")));
405 #else
406 /* date is days since 2000, timestamp is seconds since same... */
407 result = dateVal * (double) SECS_PER_DAY;
408 #endif
411 return result;
414 static TimestampTz
415 date2timestamptz(DateADT dateVal)
417 TimestampTz result;
418 struct pg_tm tt,
419 *tm = &tt;
420 int tz;
422 if (DATE_IS_NOBEGIN(dateVal))
423 TIMESTAMP_NOBEGIN(result);
424 else if (DATE_IS_NOEND(dateVal))
425 TIMESTAMP_NOEND(result);
426 else
428 j2date(dateVal + POSTGRES_EPOCH_JDATE,
429 &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
430 tm->tm_hour = 0;
431 tm->tm_min = 0;
432 tm->tm_sec = 0;
433 tz = DetermineTimeZoneOffset(tm, session_timezone);
435 #ifdef HAVE_INT64_TIMESTAMP
436 result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
437 /* Date's range is wider than timestamp's, so check for overflow */
438 if ((result - tz * USECS_PER_SEC) / USECS_PER_DAY != dateVal)
439 ereport(ERROR,
440 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
441 errmsg("date out of range for timestamp")));
442 #else
443 result = dateVal * (double) SECS_PER_DAY + tz;
444 #endif
447 return result;
452 * Crosstype comparison functions for dates
455 Datum
456 date_eq_timestamp(PG_FUNCTION_ARGS)
458 DateADT dateVal = PG_GETARG_DATEADT(0);
459 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
460 Timestamp dt1;
462 dt1 = date2timestamp(dateVal);
464 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
467 Datum
468 date_ne_timestamp(PG_FUNCTION_ARGS)
470 DateADT dateVal = PG_GETARG_DATEADT(0);
471 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
472 Timestamp dt1;
474 dt1 = date2timestamp(dateVal);
476 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
479 Datum
480 date_lt_timestamp(PG_FUNCTION_ARGS)
482 DateADT dateVal = PG_GETARG_DATEADT(0);
483 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
484 Timestamp dt1;
486 dt1 = date2timestamp(dateVal);
488 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
491 Datum
492 date_gt_timestamp(PG_FUNCTION_ARGS)
494 DateADT dateVal = PG_GETARG_DATEADT(0);
495 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
496 Timestamp dt1;
498 dt1 = date2timestamp(dateVal);
500 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
503 Datum
504 date_le_timestamp(PG_FUNCTION_ARGS)
506 DateADT dateVal = PG_GETARG_DATEADT(0);
507 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
508 Timestamp dt1;
510 dt1 = date2timestamp(dateVal);
512 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
515 Datum
516 date_ge_timestamp(PG_FUNCTION_ARGS)
518 DateADT dateVal = PG_GETARG_DATEADT(0);
519 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
520 Timestamp dt1;
522 dt1 = date2timestamp(dateVal);
524 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
527 Datum
528 date_cmp_timestamp(PG_FUNCTION_ARGS)
530 DateADT dateVal = PG_GETARG_DATEADT(0);
531 Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
532 Timestamp dt1;
534 dt1 = date2timestamp(dateVal);
536 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
539 Datum
540 date_eq_timestamptz(PG_FUNCTION_ARGS)
542 DateADT dateVal = PG_GETARG_DATEADT(0);
543 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
544 TimestampTz dt1;
546 dt1 = date2timestamptz(dateVal);
548 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
551 Datum
552 date_ne_timestamptz(PG_FUNCTION_ARGS)
554 DateADT dateVal = PG_GETARG_DATEADT(0);
555 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
556 TimestampTz dt1;
558 dt1 = date2timestamptz(dateVal);
560 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
563 Datum
564 date_lt_timestamptz(PG_FUNCTION_ARGS)
566 DateADT dateVal = PG_GETARG_DATEADT(0);
567 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
568 TimestampTz dt1;
570 dt1 = date2timestamptz(dateVal);
572 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
575 Datum
576 date_gt_timestamptz(PG_FUNCTION_ARGS)
578 DateADT dateVal = PG_GETARG_DATEADT(0);
579 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
580 TimestampTz dt1;
582 dt1 = date2timestamptz(dateVal);
584 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
587 Datum
588 date_le_timestamptz(PG_FUNCTION_ARGS)
590 DateADT dateVal = PG_GETARG_DATEADT(0);
591 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
592 TimestampTz dt1;
594 dt1 = date2timestamptz(dateVal);
596 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
599 Datum
600 date_ge_timestamptz(PG_FUNCTION_ARGS)
602 DateADT dateVal = PG_GETARG_DATEADT(0);
603 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
604 TimestampTz dt1;
606 dt1 = date2timestamptz(dateVal);
608 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
611 Datum
612 date_cmp_timestamptz(PG_FUNCTION_ARGS)
614 DateADT dateVal = PG_GETARG_DATEADT(0);
615 TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
616 TimestampTz dt1;
618 dt1 = date2timestamptz(dateVal);
620 PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
623 Datum
624 timestamp_eq_date(PG_FUNCTION_ARGS)
626 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
627 DateADT dateVal = PG_GETARG_DATEADT(1);
628 Timestamp dt2;
630 dt2 = date2timestamp(dateVal);
632 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
635 Datum
636 timestamp_ne_date(PG_FUNCTION_ARGS)
638 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
639 DateADT dateVal = PG_GETARG_DATEADT(1);
640 Timestamp dt2;
642 dt2 = date2timestamp(dateVal);
644 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
647 Datum
648 timestamp_lt_date(PG_FUNCTION_ARGS)
650 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
651 DateADT dateVal = PG_GETARG_DATEADT(1);
652 Timestamp dt2;
654 dt2 = date2timestamp(dateVal);
656 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
659 Datum
660 timestamp_gt_date(PG_FUNCTION_ARGS)
662 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
663 DateADT dateVal = PG_GETARG_DATEADT(1);
664 Timestamp dt2;
666 dt2 = date2timestamp(dateVal);
668 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
671 Datum
672 timestamp_le_date(PG_FUNCTION_ARGS)
674 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
675 DateADT dateVal = PG_GETARG_DATEADT(1);
676 Timestamp dt2;
678 dt2 = date2timestamp(dateVal);
680 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
683 Datum
684 timestamp_ge_date(PG_FUNCTION_ARGS)
686 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
687 DateADT dateVal = PG_GETARG_DATEADT(1);
688 Timestamp dt2;
690 dt2 = date2timestamp(dateVal);
692 PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
695 Datum
696 timestamp_cmp_date(PG_FUNCTION_ARGS)
698 Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
699 DateADT dateVal = PG_GETARG_DATEADT(1);
700 Timestamp dt2;
702 dt2 = date2timestamp(dateVal);
704 PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
707 Datum
708 timestamptz_eq_date(PG_FUNCTION_ARGS)
710 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
711 DateADT dateVal = PG_GETARG_DATEADT(1);
712 TimestampTz dt2;
714 dt2 = date2timestamptz(dateVal);
716 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
719 Datum
720 timestamptz_ne_date(PG_FUNCTION_ARGS)
722 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
723 DateADT dateVal = PG_GETARG_DATEADT(1);
724 TimestampTz dt2;
726 dt2 = date2timestamptz(dateVal);
728 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
731 Datum
732 timestamptz_lt_date(PG_FUNCTION_ARGS)
734 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
735 DateADT dateVal = PG_GETARG_DATEADT(1);
736 TimestampTz dt2;
738 dt2 = date2timestamptz(dateVal);
740 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
743 Datum
744 timestamptz_gt_date(PG_FUNCTION_ARGS)
746 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
747 DateADT dateVal = PG_GETARG_DATEADT(1);
748 TimestampTz dt2;
750 dt2 = date2timestamptz(dateVal);
752 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
755 Datum
756 timestamptz_le_date(PG_FUNCTION_ARGS)
758 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
759 DateADT dateVal = PG_GETARG_DATEADT(1);
760 TimestampTz dt2;
762 dt2 = date2timestamptz(dateVal);
764 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
767 Datum
768 timestamptz_ge_date(PG_FUNCTION_ARGS)
770 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
771 DateADT dateVal = PG_GETARG_DATEADT(1);
772 TimestampTz dt2;
774 dt2 = date2timestamptz(dateVal);
776 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
779 Datum
780 timestamptz_cmp_date(PG_FUNCTION_ARGS)
782 TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
783 DateADT dateVal = PG_GETARG_DATEADT(1);
784 TimestampTz dt2;
786 dt2 = date2timestamptz(dateVal);
788 PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
792 /* Add an interval to a date, giving a new date.
793 * Must handle both positive and negative intervals.
795 * We implement this by promoting the date to timestamp (without time zone)
796 * and then using the timestamp plus interval function.
798 Datum
799 date_pl_interval(PG_FUNCTION_ARGS)
801 DateADT dateVal = PG_GETARG_DATEADT(0);
802 Interval *span = PG_GETARG_INTERVAL_P(1);
803 Timestamp dateStamp;
805 dateStamp = date2timestamp(dateVal);
807 return DirectFunctionCall2(timestamp_pl_interval,
808 TimestampGetDatum(dateStamp),
809 PointerGetDatum(span));
812 /* Subtract an interval from a date, giving a new date.
813 * Must handle both positive and negative intervals.
815 * We implement this by promoting the date to timestamp (without time zone)
816 * and then using the timestamp minus interval function.
818 Datum
819 date_mi_interval(PG_FUNCTION_ARGS)
821 DateADT dateVal = PG_GETARG_DATEADT(0);
822 Interval *span = PG_GETARG_INTERVAL_P(1);
823 Timestamp dateStamp;
825 dateStamp = date2timestamp(dateVal);
827 return DirectFunctionCall2(timestamp_mi_interval,
828 TimestampGetDatum(dateStamp),
829 PointerGetDatum(span));
832 /* date_timestamp()
833 * Convert date to timestamp data type.
835 Datum
836 date_timestamp(PG_FUNCTION_ARGS)
838 DateADT dateVal = PG_GETARG_DATEADT(0);
839 Timestamp result;
841 result = date2timestamp(dateVal);
843 PG_RETURN_TIMESTAMP(result);
847 /* timestamp_date()
848 * Convert timestamp to date data type.
850 Datum
851 timestamp_date(PG_FUNCTION_ARGS)
853 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
854 DateADT result;
855 struct pg_tm tt,
856 *tm = &tt;
857 fsec_t fsec;
859 if (TIMESTAMP_IS_NOBEGIN(timestamp))
860 DATE_NOBEGIN(result);
861 else if (TIMESTAMP_IS_NOEND(timestamp))
862 DATE_NOEND(result);
863 else
865 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
866 ereport(ERROR,
867 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
868 errmsg("timestamp out of range")));
870 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
873 PG_RETURN_DATEADT(result);
877 /* date_timestamptz()
878 * Convert date to timestamp with time zone data type.
880 Datum
881 date_timestamptz(PG_FUNCTION_ARGS)
883 DateADT dateVal = PG_GETARG_DATEADT(0);
884 TimestampTz result;
886 result = date2timestamptz(dateVal);
888 PG_RETURN_TIMESTAMP(result);
892 /* timestamptz_date()
893 * Convert timestamp with time zone to date data type.
895 Datum
896 timestamptz_date(PG_FUNCTION_ARGS)
898 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
899 DateADT result;
900 struct pg_tm tt,
901 *tm = &tt;
902 fsec_t fsec;
903 int tz;
904 char *tzn;
906 if (TIMESTAMP_IS_NOBEGIN(timestamp))
907 DATE_NOBEGIN(result);
908 else if (TIMESTAMP_IS_NOEND(timestamp))
909 DATE_NOEND(result);
910 else
912 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
913 ereport(ERROR,
914 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
915 errmsg("timestamp out of range")));
917 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
920 PG_RETURN_DATEADT(result);
924 /* abstime_date()
925 * Convert abstime to date data type.
927 Datum
928 abstime_date(PG_FUNCTION_ARGS)
930 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
931 DateADT result;
932 struct pg_tm tt,
933 *tm = &tt;
934 int tz;
936 switch (abstime)
938 case INVALID_ABSTIME:
939 ereport(ERROR,
940 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
941 errmsg("cannot convert reserved abstime value to date")));
942 result = 0; /* keep compiler quiet */
943 break;
945 case NOSTART_ABSTIME:
946 DATE_NOBEGIN(result);
947 break;
949 case NOEND_ABSTIME:
950 DATE_NOEND(result);
951 break;
953 default:
954 abstime2tm(abstime, &tz, tm, NULL);
955 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
956 break;
959 PG_RETURN_DATEADT(result);
963 /*****************************************************************************
964 * Time ADT
965 *****************************************************************************/
967 Datum
968 time_in(PG_FUNCTION_ARGS)
970 char *str = PG_GETARG_CSTRING(0);
972 #ifdef NOT_USED
973 Oid typelem = PG_GETARG_OID(1);
974 #endif
975 int32 typmod = PG_GETARG_INT32(2);
976 TimeADT result;
977 fsec_t fsec;
978 struct pg_tm tt,
979 *tm = &tt;
980 int tz;
981 int nf;
982 int dterr;
983 char workbuf[MAXDATELEN + 1];
984 char *field[MAXDATEFIELDS];
985 int dtype;
986 int ftype[MAXDATEFIELDS];
988 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
989 field, ftype, MAXDATEFIELDS, &nf);
990 if (dterr == 0)
991 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
992 if (dterr != 0)
993 DateTimeParseError(dterr, str, "time");
995 tm2time(tm, fsec, &result);
996 AdjustTimeForTypmod(&result, typmod);
998 PG_RETURN_TIMEADT(result);
1001 /* tm2time()
1002 * Convert a tm structure to a time data type.
1004 static int
1005 tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
1007 #ifdef HAVE_INT64_TIMESTAMP
1008 *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
1009 * USECS_PER_SEC) + fsec;
1010 #else
1011 *result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1012 #endif
1013 return 0;
1016 /* time2tm()
1017 * Convert time data type to POSIX time structure.
1019 * For dates within the range of pg_time_t, convert to the local time zone.
1020 * If out of this range, leave as UTC (in practice that could only happen
1021 * if pg_time_t is just 32 bits) - thomas 97/05/27
1023 static int
1024 time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
1026 #ifdef HAVE_INT64_TIMESTAMP
1027 tm->tm_hour = time / USECS_PER_HOUR;
1028 time -= tm->tm_hour * USECS_PER_HOUR;
1029 tm->tm_min = time / USECS_PER_MINUTE;
1030 time -= tm->tm_min * USECS_PER_MINUTE;
1031 tm->tm_sec = time / USECS_PER_SEC;
1032 time -= tm->tm_sec * USECS_PER_SEC;
1033 *fsec = time;
1034 #else
1035 double trem;
1037 recalc:
1038 trem = time;
1039 TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
1040 TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
1041 TMODULO(trem, tm->tm_sec, 1.0);
1042 trem = TIMEROUND(trem);
1043 /* roundoff may need to propagate to higher-order fields */
1044 if (trem >= 1.0)
1046 time = ceil(time);
1047 goto recalc;
1049 *fsec = trem;
1050 #endif
1052 return 0;
1055 Datum
1056 time_out(PG_FUNCTION_ARGS)
1058 TimeADT time = PG_GETARG_TIMEADT(0);
1059 char *result;
1060 struct pg_tm tt,
1061 *tm = &tt;
1062 fsec_t fsec;
1063 char buf[MAXDATELEN + 1];
1065 time2tm(time, tm, &fsec);
1066 EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
1068 result = pstrdup(buf);
1069 PG_RETURN_CSTRING(result);
1073 * time_recv - converts external binary format to time
1075 * We make no attempt to provide compatibility between int and float
1076 * time representations ...
1078 Datum
1079 time_recv(PG_FUNCTION_ARGS)
1081 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1083 #ifdef NOT_USED
1084 Oid typelem = PG_GETARG_OID(1);
1085 #endif
1086 int32 typmod = PG_GETARG_INT32(2);
1087 TimeADT result;
1089 #ifdef HAVE_INT64_TIMESTAMP
1090 result = pq_getmsgint64(buf);
1092 if (result < INT64CONST(0) || result > USECS_PER_DAY)
1093 ereport(ERROR,
1094 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1095 errmsg("time out of range")));
1096 #else
1097 result = pq_getmsgfloat8(buf);
1099 if (result < 0 || result > (double) SECS_PER_DAY)
1100 ereport(ERROR,
1101 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1102 errmsg("time out of range")));
1103 #endif
1105 AdjustTimeForTypmod(&result, typmod);
1107 PG_RETURN_TIMEADT(result);
1111 * time_send - converts time to binary format
1113 Datum
1114 time_send(PG_FUNCTION_ARGS)
1116 TimeADT time = PG_GETARG_TIMEADT(0);
1117 StringInfoData buf;
1119 pq_begintypsend(&buf);
1120 #ifdef HAVE_INT64_TIMESTAMP
1121 pq_sendint64(&buf, time);
1122 #else
1123 pq_sendfloat8(&buf, time);
1124 #endif
1125 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1128 Datum
1129 timetypmodin(PG_FUNCTION_ARGS)
1131 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1133 PG_RETURN_INT32(anytime_typmodin(false, ta));
1136 Datum
1137 timetypmodout(PG_FUNCTION_ARGS)
1139 int32 typmod = PG_GETARG_INT32(0);
1141 PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1145 /* time_scale()
1146 * Adjust time type for specified scale factor.
1147 * Used by PostgreSQL type system to stuff columns.
1149 Datum
1150 time_scale(PG_FUNCTION_ARGS)
1152 TimeADT time = PG_GETARG_TIMEADT(0);
1153 int32 typmod = PG_GETARG_INT32(1);
1154 TimeADT result;
1156 result = time;
1157 AdjustTimeForTypmod(&result, typmod);
1159 PG_RETURN_TIMEADT(result);
1162 /* AdjustTimeForTypmod()
1163 * Force the precision of the time value to a specified value.
1164 * Uses *exactly* the same code as in AdjustTimestampForTypemod()
1165 * but we make a separate copy because those types do not
1166 * have a fundamental tie together but rather a coincidence of
1167 * implementation. - thomas
1169 static void
1170 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1172 #ifdef HAVE_INT64_TIMESTAMP
1173 static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1174 INT64CONST(1000000),
1175 INT64CONST(100000),
1176 INT64CONST(10000),
1177 INT64CONST(1000),
1178 INT64CONST(100),
1179 INT64CONST(10),
1180 INT64CONST(1)
1183 static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1184 INT64CONST(500000),
1185 INT64CONST(50000),
1186 INT64CONST(5000),
1187 INT64CONST(500),
1188 INT64CONST(50),
1189 INT64CONST(5),
1190 INT64CONST(0)
1192 #else
1193 /* note MAX_TIME_PRECISION differs in this case */
1194 static const double TimeScales[MAX_TIME_PRECISION + 1] = {
1195 1.0,
1196 10.0,
1197 100.0,
1198 1000.0,
1199 10000.0,
1200 100000.0,
1201 1000000.0,
1202 10000000.0,
1203 100000000.0,
1204 1000000000.0,
1205 10000000000.0
1207 #endif
1209 if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1212 * Note: this round-to-nearest code is not completely consistent about
1213 * rounding values that are exactly halfway between integral values.
1214 * On most platforms, rint() will implement round-to-nearest-even, but
1215 * the integer code always rounds up (away from zero). Is it worth
1216 * trying to be consistent?
1218 #ifdef HAVE_INT64_TIMESTAMP
1219 if (*time >= INT64CONST(0))
1220 *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
1221 TimeScales[typmod];
1222 else
1223 *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
1224 TimeScales[typmod]);
1225 #else
1226 *time = rint((double) *time * TimeScales[typmod]) / TimeScales[typmod];
1227 #endif
1232 Datum
1233 time_eq(PG_FUNCTION_ARGS)
1235 TimeADT time1 = PG_GETARG_TIMEADT(0);
1236 TimeADT time2 = PG_GETARG_TIMEADT(1);
1238 PG_RETURN_BOOL(time1 == time2);
1241 Datum
1242 time_ne(PG_FUNCTION_ARGS)
1244 TimeADT time1 = PG_GETARG_TIMEADT(0);
1245 TimeADT time2 = PG_GETARG_TIMEADT(1);
1247 PG_RETURN_BOOL(time1 != time2);
1250 Datum
1251 time_lt(PG_FUNCTION_ARGS)
1253 TimeADT time1 = PG_GETARG_TIMEADT(0);
1254 TimeADT time2 = PG_GETARG_TIMEADT(1);
1256 PG_RETURN_BOOL(time1 < time2);
1259 Datum
1260 time_le(PG_FUNCTION_ARGS)
1262 TimeADT time1 = PG_GETARG_TIMEADT(0);
1263 TimeADT time2 = PG_GETARG_TIMEADT(1);
1265 PG_RETURN_BOOL(time1 <= time2);
1268 Datum
1269 time_gt(PG_FUNCTION_ARGS)
1271 TimeADT time1 = PG_GETARG_TIMEADT(0);
1272 TimeADT time2 = PG_GETARG_TIMEADT(1);
1274 PG_RETURN_BOOL(time1 > time2);
1277 Datum
1278 time_ge(PG_FUNCTION_ARGS)
1280 TimeADT time1 = PG_GETARG_TIMEADT(0);
1281 TimeADT time2 = PG_GETARG_TIMEADT(1);
1283 PG_RETURN_BOOL(time1 >= time2);
1286 Datum
1287 time_cmp(PG_FUNCTION_ARGS)
1289 TimeADT time1 = PG_GETARG_TIMEADT(0);
1290 TimeADT time2 = PG_GETARG_TIMEADT(1);
1292 if (time1 < time2)
1293 PG_RETURN_INT32(-1);
1294 if (time1 > time2)
1295 PG_RETURN_INT32(1);
1296 PG_RETURN_INT32(0);
1299 Datum
1300 time_hash(PG_FUNCTION_ARGS)
1302 /* We can use either hashint8 or hashfloat8 directly */
1303 #ifdef HAVE_INT64_TIMESTAMP
1304 return hashint8(fcinfo);
1305 #else
1306 return hashfloat8(fcinfo);
1307 #endif
1310 Datum
1311 time_larger(PG_FUNCTION_ARGS)
1313 TimeADT time1 = PG_GETARG_TIMEADT(0);
1314 TimeADT time2 = PG_GETARG_TIMEADT(1);
1316 PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1319 Datum
1320 time_smaller(PG_FUNCTION_ARGS)
1322 TimeADT time1 = PG_GETARG_TIMEADT(0);
1323 TimeADT time2 = PG_GETARG_TIMEADT(1);
1325 PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1328 /* overlaps_time() --- implements the SQL92 OVERLAPS operator.
1330 * Algorithm is per SQL92 spec. This is much harder than you'd think
1331 * because the spec requires us to deliver a non-null answer in some cases
1332 * where some of the inputs are null.
1334 Datum
1335 overlaps_time(PG_FUNCTION_ARGS)
1338 * The arguments are TimeADT, but we leave them as generic Datums to avoid
1339 * dereferencing nulls (TimeADT is pass-by-reference!)
1341 Datum ts1 = PG_GETARG_DATUM(0);
1342 Datum te1 = PG_GETARG_DATUM(1);
1343 Datum ts2 = PG_GETARG_DATUM(2);
1344 Datum te2 = PG_GETARG_DATUM(3);
1345 bool ts1IsNull = PG_ARGISNULL(0);
1346 bool te1IsNull = PG_ARGISNULL(1);
1347 bool ts2IsNull = PG_ARGISNULL(2);
1348 bool te2IsNull = PG_ARGISNULL(3);
1350 #define TIMEADT_GT(t1,t2) \
1351 (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1352 #define TIMEADT_LT(t1,t2) \
1353 (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1356 * If both endpoints of interval 1 are null, the result is null (unknown).
1357 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1358 * take ts1 as the lesser endpoint.
1360 if (ts1IsNull)
1362 if (te1IsNull)
1363 PG_RETURN_NULL();
1364 /* swap null for non-null */
1365 ts1 = te1;
1366 te1IsNull = true;
1368 else if (!te1IsNull)
1370 if (TIMEADT_GT(ts1, te1))
1372 Datum tt = ts1;
1374 ts1 = te1;
1375 te1 = tt;
1379 /* Likewise for interval 2. */
1380 if (ts2IsNull)
1382 if (te2IsNull)
1383 PG_RETURN_NULL();
1384 /* swap null for non-null */
1385 ts2 = te2;
1386 te2IsNull = true;
1388 else if (!te2IsNull)
1390 if (TIMEADT_GT(ts2, te2))
1392 Datum tt = ts2;
1394 ts2 = te2;
1395 te2 = tt;
1400 * At this point neither ts1 nor ts2 is null, so we can consider three
1401 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1403 if (TIMEADT_GT(ts1, ts2))
1406 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1407 * in the presence of nulls it's not quite completely so.
1409 if (te2IsNull)
1410 PG_RETURN_NULL();
1411 if (TIMEADT_LT(ts1, te2))
1412 PG_RETURN_BOOL(true);
1413 if (te1IsNull)
1414 PG_RETURN_NULL();
1417 * If te1 is not null then we had ts1 <= te1 above, and we just found
1418 * ts1 >= te2, hence te1 >= te2.
1420 PG_RETURN_BOOL(false);
1422 else if (TIMEADT_LT(ts1, ts2))
1424 /* This case is ts2 < te1 OR te2 < te1 */
1425 if (te1IsNull)
1426 PG_RETURN_NULL();
1427 if (TIMEADT_LT(ts2, te1))
1428 PG_RETURN_BOOL(true);
1429 if (te2IsNull)
1430 PG_RETURN_NULL();
1433 * If te2 is not null then we had ts2 <= te2 above, and we just found
1434 * ts2 >= te1, hence te2 >= te1.
1436 PG_RETURN_BOOL(false);
1438 else
1441 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1442 * rather silly way of saying "true if both are nonnull, else null".
1444 if (te1IsNull || te2IsNull)
1445 PG_RETURN_NULL();
1446 PG_RETURN_BOOL(true);
1449 #undef TIMEADT_GT
1450 #undef TIMEADT_LT
1453 /* timestamp_time()
1454 * Convert timestamp to time data type.
1456 Datum
1457 timestamp_time(PG_FUNCTION_ARGS)
1459 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1460 TimeADT result;
1461 struct pg_tm tt,
1462 *tm = &tt;
1463 fsec_t fsec;
1465 if (TIMESTAMP_NOT_FINITE(timestamp))
1466 PG_RETURN_NULL();
1468 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1469 ereport(ERROR,
1470 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1471 errmsg("timestamp out of range")));
1473 #ifdef HAVE_INT64_TIMESTAMP
1476 * Could also do this with time = (timestamp / USECS_PER_DAY *
1477 * USECS_PER_DAY) - timestamp;
1479 result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1480 USECS_PER_SEC) + fsec;
1481 #else
1482 result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1483 #endif
1485 PG_RETURN_TIMEADT(result);
1488 /* timestamptz_time()
1489 * Convert timestamptz to time data type.
1491 Datum
1492 timestamptz_time(PG_FUNCTION_ARGS)
1494 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1495 TimeADT result;
1496 struct pg_tm tt,
1497 *tm = &tt;
1498 int tz;
1499 fsec_t fsec;
1500 char *tzn;
1502 if (TIMESTAMP_NOT_FINITE(timestamp))
1503 PG_RETURN_NULL();
1505 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
1506 ereport(ERROR,
1507 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1508 errmsg("timestamp out of range")));
1510 #ifdef HAVE_INT64_TIMESTAMP
1513 * Could also do this with time = (timestamp / USECS_PER_DAY *
1514 * USECS_PER_DAY) - timestamp;
1516 result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1517 USECS_PER_SEC) + fsec;
1518 #else
1519 result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1520 #endif
1522 PG_RETURN_TIMEADT(result);
1525 /* datetime_timestamp()
1526 * Convert date and time to timestamp data type.
1528 Datum
1529 datetime_timestamp(PG_FUNCTION_ARGS)
1531 DateADT date = PG_GETARG_DATEADT(0);
1532 TimeADT time = PG_GETARG_TIMEADT(1);
1533 Timestamp result;
1535 result = date2timestamp(date);
1536 if (!TIMESTAMP_NOT_FINITE(result))
1537 result += time;
1539 PG_RETURN_TIMESTAMP(result);
1542 /* time_interval()
1543 * Convert time to interval data type.
1545 Datum
1546 time_interval(PG_FUNCTION_ARGS)
1548 TimeADT time = PG_GETARG_TIMEADT(0);
1549 Interval *result;
1551 result = (Interval *) palloc(sizeof(Interval));
1553 result->time = time;
1554 result->day = 0;
1555 result->month = 0;
1557 PG_RETURN_INTERVAL_P(result);
1560 /* interval_time()
1561 * Convert interval to time data type.
1563 * This is defined as producing the fractional-day portion of the interval.
1564 * Therefore, we can just ignore the months field. It is not real clear
1565 * what to do with negative intervals, but we choose to subtract the floor,
1566 * so that, say, '-2 hours' becomes '22:00:00'.
1568 Datum
1569 interval_time(PG_FUNCTION_ARGS)
1571 Interval *span = PG_GETARG_INTERVAL_P(0);
1572 TimeADT result;
1574 #ifdef HAVE_INT64_TIMESTAMP
1575 int64 days;
1577 result = span->time;
1578 if (result >= USECS_PER_DAY)
1580 days = result / USECS_PER_DAY;
1581 result -= days * USECS_PER_DAY;
1583 else if (result < 0)
1585 days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
1586 result += days * USECS_PER_DAY;
1588 #else
1589 result = span->time;
1590 if (result >= (double) SECS_PER_DAY || result < 0)
1591 result -= floor(result / (double) SECS_PER_DAY) * (double) SECS_PER_DAY;
1592 #endif
1594 PG_RETURN_TIMEADT(result);
1597 /* time_mi_time()
1598 * Subtract two times to produce an interval.
1600 Datum
1601 time_mi_time(PG_FUNCTION_ARGS)
1603 TimeADT time1 = PG_GETARG_TIMEADT(0);
1604 TimeADT time2 = PG_GETARG_TIMEADT(1);
1605 Interval *result;
1607 result = (Interval *) palloc(sizeof(Interval));
1609 result->month = 0;
1610 result->day = 0;
1611 result->time = time1 - time2;
1613 PG_RETURN_INTERVAL_P(result);
1616 /* time_pl_interval()
1617 * Add interval to time.
1619 Datum
1620 time_pl_interval(PG_FUNCTION_ARGS)
1622 TimeADT time = PG_GETARG_TIMEADT(0);
1623 Interval *span = PG_GETARG_INTERVAL_P(1);
1624 TimeADT result;
1626 #ifdef HAVE_INT64_TIMESTAMP
1627 result = time + span->time;
1628 result -= result / USECS_PER_DAY * USECS_PER_DAY;
1629 if (result < INT64CONST(0))
1630 result += USECS_PER_DAY;
1631 #else
1632 TimeADT time1;
1634 result = time + span->time;
1635 TMODULO(result, time1, (double) SECS_PER_DAY);
1636 if (result < 0)
1637 result += SECS_PER_DAY;
1638 #endif
1640 PG_RETURN_TIMEADT(result);
1643 /* time_mi_interval()
1644 * Subtract interval from time.
1646 Datum
1647 time_mi_interval(PG_FUNCTION_ARGS)
1649 TimeADT time = PG_GETARG_TIMEADT(0);
1650 Interval *span = PG_GETARG_INTERVAL_P(1);
1651 TimeADT result;
1653 #ifdef HAVE_INT64_TIMESTAMP
1654 result = time - span->time;
1655 result -= result / USECS_PER_DAY * USECS_PER_DAY;
1656 if (result < INT64CONST(0))
1657 result += USECS_PER_DAY;
1658 #else
1659 TimeADT time1;
1661 result = time - span->time;
1662 TMODULO(result, time1, (double) SECS_PER_DAY);
1663 if (result < 0)
1664 result += SECS_PER_DAY;
1665 #endif
1667 PG_RETURN_TIMEADT(result);
1671 /* time_part()
1672 * Extract specified field from time type.
1674 Datum
1675 time_part(PG_FUNCTION_ARGS)
1677 text *units = PG_GETARG_TEXT_PP(0);
1678 TimeADT time = PG_GETARG_TIMEADT(1);
1679 float8 result;
1680 int type,
1681 val;
1682 char *lowunits;
1684 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1685 VARSIZE_ANY_EXHDR(units),
1686 false);
1688 type = DecodeUnits(0, lowunits, &val);
1689 if (type == UNKNOWN_FIELD)
1690 type = DecodeSpecial(0, lowunits, &val);
1692 if (type == UNITS)
1694 fsec_t fsec;
1695 struct pg_tm tt,
1696 *tm = &tt;
1698 time2tm(time, tm, &fsec);
1700 switch (val)
1702 case DTK_MICROSEC:
1703 #ifdef HAVE_INT64_TIMESTAMP
1704 result = tm->tm_sec * USECS_PER_SEC + fsec;
1705 #else
1706 result = (tm->tm_sec + fsec) * 1000000;
1707 #endif
1708 break;
1710 case DTK_MILLISEC:
1711 #ifdef HAVE_INT64_TIMESTAMP
1712 result = tm->tm_sec * INT64CONST(1000) + fsec / INT64CONST(1000);
1713 #else
1714 result = (tm->tm_sec + fsec) * 1000;
1715 #endif
1716 break;
1718 case DTK_SECOND:
1719 #ifdef HAVE_INT64_TIMESTAMP
1720 result = tm->tm_sec + fsec / USECS_PER_SEC;
1721 #else
1722 result = tm->tm_sec + fsec;
1723 #endif
1724 break;
1726 case DTK_MINUTE:
1727 result = tm->tm_min;
1728 break;
1730 case DTK_HOUR:
1731 result = tm->tm_hour;
1732 break;
1734 case DTK_TZ:
1735 case DTK_TZ_MINUTE:
1736 case DTK_TZ_HOUR:
1737 case DTK_DAY:
1738 case DTK_MONTH:
1739 case DTK_QUARTER:
1740 case DTK_YEAR:
1741 case DTK_DECADE:
1742 case DTK_CENTURY:
1743 case DTK_MILLENNIUM:
1744 case DTK_ISOYEAR:
1745 default:
1746 ereport(ERROR,
1747 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1748 errmsg("\"time\" units \"%s\" not recognized",
1749 lowunits)));
1750 result = 0;
1753 else if (type == RESERV && val == DTK_EPOCH)
1755 #ifdef HAVE_INT64_TIMESTAMP
1756 result = time / 1000000.0;
1757 #else
1758 result = time;
1759 #endif
1761 else
1763 ereport(ERROR,
1764 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1765 errmsg("\"time\" units \"%s\" not recognized",
1766 lowunits)));
1767 result = 0;
1770 PG_RETURN_FLOAT8(result);
1774 /*****************************************************************************
1775 * Time With Time Zone ADT
1776 *****************************************************************************/
1778 /* tm2timetz()
1779 * Convert a tm structure to a time data type.
1781 static int
1782 tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
1784 #ifdef HAVE_INT64_TIMESTAMP
1785 result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
1786 USECS_PER_SEC) + fsec;
1787 #else
1788 result->time = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
1789 #endif
1790 result->zone = tz;
1792 return 0;
1795 Datum
1796 timetz_in(PG_FUNCTION_ARGS)
1798 char *str = PG_GETARG_CSTRING(0);
1800 #ifdef NOT_USED
1801 Oid typelem = PG_GETARG_OID(1);
1802 #endif
1803 int32 typmod = PG_GETARG_INT32(2);
1804 TimeTzADT *result;
1805 fsec_t fsec;
1806 struct pg_tm tt,
1807 *tm = &tt;
1808 int tz;
1809 int nf;
1810 int dterr;
1811 char workbuf[MAXDATELEN + 1];
1812 char *field[MAXDATEFIELDS];
1813 int dtype;
1814 int ftype[MAXDATEFIELDS];
1816 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1817 field, ftype, MAXDATEFIELDS, &nf);
1818 if (dterr == 0)
1819 dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
1820 if (dterr != 0)
1821 DateTimeParseError(dterr, str, "time with time zone");
1823 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1824 tm2timetz(tm, fsec, tz, result);
1825 AdjustTimeForTypmod(&(result->time), typmod);
1827 PG_RETURN_TIMETZADT_P(result);
1830 Datum
1831 timetz_out(PG_FUNCTION_ARGS)
1833 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1834 char *result;
1835 struct pg_tm tt,
1836 *tm = &tt;
1837 fsec_t fsec;
1838 int tz;
1839 char buf[MAXDATELEN + 1];
1841 timetz2tm(time, tm, &fsec, &tz);
1842 EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
1844 result = pstrdup(buf);
1845 PG_RETURN_CSTRING(result);
1849 * timetz_recv - converts external binary format to timetz
1851 Datum
1852 timetz_recv(PG_FUNCTION_ARGS)
1854 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1856 #ifdef NOT_USED
1857 Oid typelem = PG_GETARG_OID(1);
1858 #endif
1859 int32 typmod = PG_GETARG_INT32(2);
1860 TimeTzADT *result;
1862 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1864 #ifdef HAVE_INT64_TIMESTAMP
1865 result->time = pq_getmsgint64(buf);
1867 if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
1868 ereport(ERROR,
1869 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1870 errmsg("time out of range")));
1871 #else
1872 result->time = pq_getmsgfloat8(buf);
1874 if (result->time < 0 || result->time > (double) SECS_PER_DAY)
1875 ereport(ERROR,
1876 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1877 errmsg("time out of range")));
1878 #endif
1880 result->zone = pq_getmsgint(buf, sizeof(result->zone));
1882 /* we allow GMT displacements up to 14:59:59, cf DecodeTimezone() */
1883 if (result->zone <= -15 * SECS_PER_HOUR ||
1884 result->zone >= 15 * SECS_PER_HOUR)
1885 ereport(ERROR,
1886 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
1887 errmsg("time zone displacement out of range")));
1889 AdjustTimeForTypmod(&(result->time), typmod);
1891 PG_RETURN_TIMETZADT_P(result);
1895 * timetz_send - converts timetz to binary format
1897 Datum
1898 timetz_send(PG_FUNCTION_ARGS)
1900 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1901 StringInfoData buf;
1903 pq_begintypsend(&buf);
1904 #ifdef HAVE_INT64_TIMESTAMP
1905 pq_sendint64(&buf, time->time);
1906 #else
1907 pq_sendfloat8(&buf, time->time);
1908 #endif
1909 pq_sendint(&buf, time->zone, sizeof(time->zone));
1910 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1913 Datum
1914 timetztypmodin(PG_FUNCTION_ARGS)
1916 ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1918 PG_RETURN_INT32(anytime_typmodin(true, ta));
1921 Datum
1922 timetztypmodout(PG_FUNCTION_ARGS)
1924 int32 typmod = PG_GETARG_INT32(0);
1926 PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
1930 /* timetz2tm()
1931 * Convert TIME WITH TIME ZONE data type to POSIX time structure.
1933 static int
1934 timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp)
1936 TimeOffset trem = time->time;
1938 #ifdef HAVE_INT64_TIMESTAMP
1939 tm->tm_hour = trem / USECS_PER_HOUR;
1940 trem -= tm->tm_hour * USECS_PER_HOUR;
1941 tm->tm_min = trem / USECS_PER_MINUTE;
1942 trem -= tm->tm_min * USECS_PER_MINUTE;
1943 tm->tm_sec = trem / USECS_PER_SEC;
1944 *fsec = trem - tm->tm_sec * USECS_PER_SEC;
1945 #else
1946 recalc:
1947 TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
1948 TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
1949 TMODULO(trem, tm->tm_sec, 1.0);
1950 trem = TIMEROUND(trem);
1951 /* roundoff may need to propagate to higher-order fields */
1952 if (trem >= 1.0)
1954 trem = ceil(time->time);
1955 goto recalc;
1957 *fsec = trem;
1958 #endif
1960 if (tzp != NULL)
1961 *tzp = time->zone;
1963 return 0;
1966 /* timetz_scale()
1967 * Adjust time type for specified scale factor.
1968 * Used by PostgreSQL type system to stuff columns.
1970 Datum
1971 timetz_scale(PG_FUNCTION_ARGS)
1973 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
1974 int32 typmod = PG_GETARG_INT32(1);
1975 TimeTzADT *result;
1977 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
1979 result->time = time->time;
1980 result->zone = time->zone;
1982 AdjustTimeForTypmod(&(result->time), typmod);
1984 PG_RETURN_TIMETZADT_P(result);
1988 static int
1989 timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
1991 TimeOffset t1,
1994 /* Primary sort is by true (GMT-equivalent) time */
1995 #ifdef HAVE_INT64_TIMESTAMP
1996 t1 = time1->time + (time1->zone * USECS_PER_SEC);
1997 t2 = time2->time + (time2->zone * USECS_PER_SEC);
1998 #else
1999 t1 = time1->time + time1->zone;
2000 t2 = time2->time + time2->zone;
2001 #endif
2003 if (t1 > t2)
2004 return 1;
2005 if (t1 < t2)
2006 return -1;
2009 * If same GMT time, sort by timezone; we only want to say that two
2010 * timetz's are equal if both the time and zone parts are equal.
2012 if (time1->zone > time2->zone)
2013 return 1;
2014 if (time1->zone < time2->zone)
2015 return -1;
2017 return 0;
2020 Datum
2021 timetz_eq(PG_FUNCTION_ARGS)
2023 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2024 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2026 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2029 Datum
2030 timetz_ne(PG_FUNCTION_ARGS)
2032 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2033 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2035 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2038 Datum
2039 timetz_lt(PG_FUNCTION_ARGS)
2041 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2042 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2044 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2047 Datum
2048 timetz_le(PG_FUNCTION_ARGS)
2050 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2051 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2053 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2056 Datum
2057 timetz_gt(PG_FUNCTION_ARGS)
2059 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2060 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2062 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2065 Datum
2066 timetz_ge(PG_FUNCTION_ARGS)
2068 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2069 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2071 PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2074 Datum
2075 timetz_cmp(PG_FUNCTION_ARGS)
2077 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2078 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2080 PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2083 Datum
2084 timetz_hash(PG_FUNCTION_ARGS)
2086 TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
2087 uint32 thash;
2090 * To avoid any problems with padding bytes in the struct, we figure the
2091 * field hashes separately and XOR them. This also provides a convenient
2092 * framework for dealing with the fact that the time field might be either
2093 * double or int64.
2095 #ifdef HAVE_INT64_TIMESTAMP
2096 thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2097 Int64GetDatumFast(key->time)));
2098 #else
2099 thash = DatumGetUInt32(DirectFunctionCall1(hashfloat8,
2100 Float8GetDatumFast(key->time)));
2101 #endif
2102 thash ^= DatumGetUInt32(hash_uint32(key->zone));
2103 PG_RETURN_UINT32(thash);
2106 Datum
2107 timetz_larger(PG_FUNCTION_ARGS)
2109 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2110 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2111 TimeTzADT *result;
2113 if (timetz_cmp_internal(time1, time2) > 0)
2114 result = time1;
2115 else
2116 result = time2;
2117 PG_RETURN_TIMETZADT_P(result);
2120 Datum
2121 timetz_smaller(PG_FUNCTION_ARGS)
2123 TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2124 TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2125 TimeTzADT *result;
2127 if (timetz_cmp_internal(time1, time2) < 0)
2128 result = time1;
2129 else
2130 result = time2;
2131 PG_RETURN_TIMETZADT_P(result);
2134 /* timetz_pl_interval()
2135 * Add interval to timetz.
2137 Datum
2138 timetz_pl_interval(PG_FUNCTION_ARGS)
2140 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2141 Interval *span = PG_GETARG_INTERVAL_P(1);
2142 TimeTzADT *result;
2144 #ifndef HAVE_INT64_TIMESTAMP
2145 TimeTzADT time1;
2146 #endif
2148 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2150 #ifdef HAVE_INT64_TIMESTAMP
2151 result->time = time->time + span->time;
2152 result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2153 if (result->time < INT64CONST(0))
2154 result->time += USECS_PER_DAY;
2155 #else
2156 result->time = time->time + span->time;
2157 TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
2158 if (result->time < 0)
2159 result->time += SECS_PER_DAY;
2160 #endif
2162 result->zone = time->zone;
2164 PG_RETURN_TIMETZADT_P(result);
2167 /* timetz_mi_interval()
2168 * Subtract interval from timetz.
2170 Datum
2171 timetz_mi_interval(PG_FUNCTION_ARGS)
2173 TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2174 Interval *span = PG_GETARG_INTERVAL_P(1);
2175 TimeTzADT *result;
2177 #ifndef HAVE_INT64_TIMESTAMP
2178 TimeTzADT time1;
2179 #endif
2181 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2183 #ifdef HAVE_INT64_TIMESTAMP
2184 result->time = time->time - span->time;
2185 result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2186 if (result->time < INT64CONST(0))
2187 result->time += USECS_PER_DAY;
2188 #else
2189 result->time = time->time - span->time;
2190 TMODULO(result->time, time1.time, (double) SECS_PER_DAY);
2191 if (result->time < 0)
2192 result->time += SECS_PER_DAY;
2193 #endif
2195 result->zone = time->zone;
2197 PG_RETURN_TIMETZADT_P(result);
2200 /* overlaps_timetz() --- implements the SQL92 OVERLAPS operator.
2202 * Algorithm is per SQL92 spec. This is much harder than you'd think
2203 * because the spec requires us to deliver a non-null answer in some cases
2204 * where some of the inputs are null.
2206 Datum
2207 overlaps_timetz(PG_FUNCTION_ARGS)
2210 * The arguments are TimeTzADT *, but we leave them as generic Datums for
2211 * convenience of notation --- and to avoid dereferencing nulls.
2213 Datum ts1 = PG_GETARG_DATUM(0);
2214 Datum te1 = PG_GETARG_DATUM(1);
2215 Datum ts2 = PG_GETARG_DATUM(2);
2216 Datum te2 = PG_GETARG_DATUM(3);
2217 bool ts1IsNull = PG_ARGISNULL(0);
2218 bool te1IsNull = PG_ARGISNULL(1);
2219 bool ts2IsNull = PG_ARGISNULL(2);
2220 bool te2IsNull = PG_ARGISNULL(3);
2222 #define TIMETZ_GT(t1,t2) \
2223 DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2224 #define TIMETZ_LT(t1,t2) \
2225 DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2228 * If both endpoints of interval 1 are null, the result is null (unknown).
2229 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2230 * take ts1 as the lesser endpoint.
2232 if (ts1IsNull)
2234 if (te1IsNull)
2235 PG_RETURN_NULL();
2236 /* swap null for non-null */
2237 ts1 = te1;
2238 te1IsNull = true;
2240 else if (!te1IsNull)
2242 if (TIMETZ_GT(ts1, te1))
2244 Datum tt = ts1;
2246 ts1 = te1;
2247 te1 = tt;
2251 /* Likewise for interval 2. */
2252 if (ts2IsNull)
2254 if (te2IsNull)
2255 PG_RETURN_NULL();
2256 /* swap null for non-null */
2257 ts2 = te2;
2258 te2IsNull = true;
2260 else if (!te2IsNull)
2262 if (TIMETZ_GT(ts2, te2))
2264 Datum tt = ts2;
2266 ts2 = te2;
2267 te2 = tt;
2272 * At this point neither ts1 nor ts2 is null, so we can consider three
2273 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2275 if (TIMETZ_GT(ts1, ts2))
2278 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2279 * in the presence of nulls it's not quite completely so.
2281 if (te2IsNull)
2282 PG_RETURN_NULL();
2283 if (TIMETZ_LT(ts1, te2))
2284 PG_RETURN_BOOL(true);
2285 if (te1IsNull)
2286 PG_RETURN_NULL();
2289 * If te1 is not null then we had ts1 <= te1 above, and we just found
2290 * ts1 >= te2, hence te1 >= te2.
2292 PG_RETURN_BOOL(false);
2294 else if (TIMETZ_LT(ts1, ts2))
2296 /* This case is ts2 < te1 OR te2 < te1 */
2297 if (te1IsNull)
2298 PG_RETURN_NULL();
2299 if (TIMETZ_LT(ts2, te1))
2300 PG_RETURN_BOOL(true);
2301 if (te2IsNull)
2302 PG_RETURN_NULL();
2305 * If te2 is not null then we had ts2 <= te2 above, and we just found
2306 * ts2 >= te1, hence te2 >= te1.
2308 PG_RETURN_BOOL(false);
2310 else
2313 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2314 * rather silly way of saying "true if both are nonnull, else null".
2316 if (te1IsNull || te2IsNull)
2317 PG_RETURN_NULL();
2318 PG_RETURN_BOOL(true);
2321 #undef TIMETZ_GT
2322 #undef TIMETZ_LT
2326 Datum
2327 timetz_time(PG_FUNCTION_ARGS)
2329 TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
2330 TimeADT result;
2332 /* swallow the time zone and just return the time */
2333 result = timetz->time;
2335 PG_RETURN_TIMEADT(result);
2339 Datum
2340 time_timetz(PG_FUNCTION_ARGS)
2342 TimeADT time = PG_GETARG_TIMEADT(0);
2343 TimeTzADT *result;
2344 struct pg_tm tt,
2345 *tm = &tt;
2346 fsec_t fsec;
2347 int tz;
2349 GetCurrentDateTime(tm);
2350 time2tm(time, tm, &fsec);
2351 tz = DetermineTimeZoneOffset(tm, session_timezone);
2353 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2355 result->time = time;
2356 result->zone = tz;
2358 PG_RETURN_TIMETZADT_P(result);
2362 /* timestamptz_timetz()
2363 * Convert timestamp to timetz data type.
2365 Datum
2366 timestamptz_timetz(PG_FUNCTION_ARGS)
2368 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2369 TimeTzADT *result;
2370 struct pg_tm tt,
2371 *tm = &tt;
2372 int tz;
2373 fsec_t fsec;
2374 char *tzn;
2376 if (TIMESTAMP_NOT_FINITE(timestamp))
2377 PG_RETURN_NULL();
2379 if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
2380 ereport(ERROR,
2381 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2382 errmsg("timestamp out of range")));
2384 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2386 tm2timetz(tm, fsec, tz, result);
2388 PG_RETURN_TIMETZADT_P(result);
2392 /* datetimetz_timestamptz()
2393 * Convert date and timetz to timestamp with time zone data type.
2394 * Timestamp is stored in GMT, so add the time zone
2395 * stored with the timetz to the result.
2396 * - thomas 2000-03-10
2398 Datum
2399 datetimetz_timestamptz(PG_FUNCTION_ARGS)
2401 DateADT date = PG_GETARG_DATEADT(0);
2402 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2403 TimestampTz result;
2405 if (DATE_IS_NOBEGIN(date))
2406 TIMESTAMP_NOBEGIN(result);
2407 else if (DATE_IS_NOEND(date))
2408 TIMESTAMP_NOEND(result);
2409 else
2411 #ifdef HAVE_INT64_TIMESTAMP
2412 result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
2413 #else
2414 result = date * (double) SECS_PER_DAY + time->time + time->zone;
2415 #endif
2418 PG_RETURN_TIMESTAMP(result);
2422 /* timetz_part()
2423 * Extract specified field from time type.
2425 Datum
2426 timetz_part(PG_FUNCTION_ARGS)
2428 text *units = PG_GETARG_TEXT_PP(0);
2429 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2430 float8 result;
2431 int type,
2432 val;
2433 char *lowunits;
2435 lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2436 VARSIZE_ANY_EXHDR(units),
2437 false);
2439 type = DecodeUnits(0, lowunits, &val);
2440 if (type == UNKNOWN_FIELD)
2441 type = DecodeSpecial(0, lowunits, &val);
2443 if (type == UNITS)
2445 double dummy;
2446 int tz;
2447 fsec_t fsec;
2448 struct pg_tm tt,
2449 *tm = &tt;
2451 timetz2tm(time, tm, &fsec, &tz);
2453 switch (val)
2455 case DTK_TZ:
2456 result = -tz;
2457 break;
2459 case DTK_TZ_MINUTE:
2460 result = -tz;
2461 result /= SECS_PER_MINUTE;
2462 FMODULO(result, dummy, (double) SECS_PER_MINUTE);
2463 break;
2465 case DTK_TZ_HOUR:
2466 dummy = -tz;
2467 FMODULO(dummy, result, (double) SECS_PER_HOUR);
2468 break;
2470 case DTK_MICROSEC:
2471 #ifdef HAVE_INT64_TIMESTAMP
2472 result = tm->tm_sec * USECS_PER_SEC + fsec;
2473 #else
2474 result = (tm->tm_sec + fsec) * 1000000;
2475 #endif
2476 break;
2478 case DTK_MILLISEC:
2479 #ifdef HAVE_INT64_TIMESTAMP
2480 result = tm->tm_sec * INT64CONST(1000) + fsec / INT64CONST(1000);
2481 #else
2482 result = (tm->tm_sec + fsec) * 1000;
2483 #endif
2484 break;
2486 case DTK_SECOND:
2487 #ifdef HAVE_INT64_TIMESTAMP
2488 result = tm->tm_sec + fsec / USECS_PER_SEC;
2489 #else
2490 result = tm->tm_sec + fsec;
2491 #endif
2492 break;
2494 case DTK_MINUTE:
2495 result = tm->tm_min;
2496 break;
2498 case DTK_HOUR:
2499 result = tm->tm_hour;
2500 break;
2502 case DTK_DAY:
2503 case DTK_MONTH:
2504 case DTK_QUARTER:
2505 case DTK_YEAR:
2506 case DTK_DECADE:
2507 case DTK_CENTURY:
2508 case DTK_MILLENNIUM:
2509 default:
2510 ereport(ERROR,
2511 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2512 errmsg("\"time with time zone\" units \"%s\" not recognized",
2513 lowunits)));
2514 result = 0;
2517 else if (type == RESERV && val == DTK_EPOCH)
2519 #ifdef HAVE_INT64_TIMESTAMP
2520 result = time->time / 1000000.0 + time->zone;
2521 #else
2522 result = time->time + time->zone;
2523 #endif
2525 else
2527 ereport(ERROR,
2528 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2529 errmsg("\"time with time zone\" units \"%s\" not recognized",
2530 lowunits)));
2531 result = 0;
2534 PG_RETURN_FLOAT8(result);
2537 /* timetz_zone()
2538 * Encode time with time zone type with specified time zone.
2539 * Applies DST rules as of the current date.
2541 Datum
2542 timetz_zone(PG_FUNCTION_ARGS)
2544 text *zone = PG_GETARG_TEXT_PP(0);
2545 TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
2546 TimeTzADT *result;
2547 int tz;
2548 char tzname[TZ_STRLEN_MAX + 1];
2549 char *lowzone;
2550 int type,
2551 val;
2552 pg_tz *tzp;
2555 * Look up the requested timezone. First we look in the date token table
2556 * (to handle cases like "EST"), and if that fails, we look in the
2557 * timezone database (to handle cases like "America/New_York"). (This
2558 * matches the order in which timestamp input checks the cases; it's
2559 * important because the timezone database unwisely uses a few zone names
2560 * that are identical to offset abbreviations.)
2562 text_to_cstring_buffer(zone, tzname, sizeof(tzname));
2563 lowzone = downcase_truncate_identifier(tzname,
2564 strlen(tzname),
2565 false);
2567 type = DecodeSpecial(0, lowzone, &val);
2569 if (type == TZ || type == DTZ)
2570 tz = val * 60;
2571 else
2573 tzp = pg_tzset(tzname);
2574 if (tzp)
2576 /* Get the offset-from-GMT that is valid today for the zone */
2577 pg_time_t now = (pg_time_t) time(NULL);
2578 struct pg_tm *tm;
2580 tm = pg_localtime(&now, tzp);
2581 tz = -tm->tm_gmtoff;
2583 else
2585 ereport(ERROR,
2586 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2587 errmsg("time zone \"%s\" not recognized", tzname)));
2588 tz = 0; /* keep compiler quiet */
2592 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2594 #ifdef HAVE_INT64_TIMESTAMP
2595 result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
2596 while (result->time < INT64CONST(0))
2597 result->time += USECS_PER_DAY;
2598 while (result->time >= USECS_PER_DAY)
2599 result->time -= USECS_PER_DAY;
2600 #else
2601 result->time = t->time + (t->zone - tz);
2602 while (result->time < 0)
2603 result->time += SECS_PER_DAY;
2604 while (result->time >= SECS_PER_DAY)
2605 result->time -= SECS_PER_DAY;
2606 #endif
2608 result->zone = tz;
2610 PG_RETURN_TIMETZADT_P(result);
2613 /* timetz_izone()
2614 * Encode time with time zone type with specified time interval as time zone.
2616 Datum
2617 timetz_izone(PG_FUNCTION_ARGS)
2619 Interval *zone = PG_GETARG_INTERVAL_P(0);
2620 TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2621 TimeTzADT *result;
2622 int tz;
2624 if (zone->month != 0)
2625 ereport(ERROR,
2626 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2627 errmsg("\"interval\" time zone \"%s\" not valid",
2628 DatumGetCString(DirectFunctionCall1(interval_out,
2629 PointerGetDatum(zone))))));
2631 #ifdef HAVE_INT64_TIMESTAMP
2632 tz = -(zone->time / USECS_PER_SEC);
2633 #else
2634 tz = -(zone->time);
2635 #endif
2637 result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2639 #ifdef HAVE_INT64_TIMESTAMP
2640 result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
2641 while (result->time < INT64CONST(0))
2642 result->time += USECS_PER_DAY;
2643 while (result->time >= USECS_PER_DAY)
2644 result->time -= USECS_PER_DAY;
2645 #else
2646 result->time = time->time + (time->zone - tz);
2647 while (result->time < 0)
2648 result->time += SECS_PER_DAY;
2649 while (result->time >= SECS_PER_DAY)
2650 result->time -= SECS_PER_DAY;
2651 #endif
2653 result->zone = tz;
2655 PG_RETURN_TIMETZADT_P(result);