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