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