1 /*-------------------------------------------------------------------------
4 * implements DATE and TIME data types specified in SQL-92 standard
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
13 *-------------------------------------------------------------------------
23 #include "access/hash.h"
24 #include "libpq/pqformat.h"
25 #include "miscadmin.h"
26 #include "parser/scansup.h"
27 #include "utils/array.h"
28 #include "utils/builtins.h"
29 #include "utils/date.h"
30 #include "utils/nabstime.h"
33 * gcc's -ffast-math switch breaks routines that expect exact results from
34 * expressions like timeval / SECS_PER_HOUR, where timeval is double.
37 #error -ffast-math is known to break this code
41 static void EncodeSpecialDate(DateADT dt
, char *str
);
42 static int time2tm(TimeADT time
, struct pg_tm
* tm
, fsec_t
*fsec
);
43 static int timetz2tm(TimeTzADT
*time
, struct pg_tm
* tm
, fsec_t
*fsec
, int *tzp
);
44 static int tm2time(struct pg_tm
* tm
, fsec_t fsec
, TimeADT
*result
);
45 static int tm2timetz(struct pg_tm
* tm
, fsec_t fsec
, int tz
, TimeTzADT
*result
);
46 static void AdjustTimeForTypmod(TimeADT
*time
, int32 typmod
);
49 /* common code for timetypmodin and timetztypmodin */
51 anytime_typmodin(bool istz
, ArrayType
*ta
)
57 tl
= ArrayGetIntegerTypmods(ta
, &n
);
60 * we're not too tense about good error message here because grammar
61 * shouldn't allow wrong number of modifiers for TIME
65 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
66 errmsg("invalid type modifier")));
70 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
71 errmsg("TIME(%d)%s precision must not be negative",
72 *tl
, (istz
? " WITH TIME ZONE" : ""))));
73 if (*tl
> MAX_TIME_PRECISION
)
76 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
77 errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
78 *tl
, (istz
? " WITH TIME ZONE" : ""),
79 MAX_TIME_PRECISION
)));
80 typmod
= MAX_TIME_PRECISION
;
88 /* common code for timetypmodout and timetztypmodout */
90 anytime_typmodout(bool istz
, int32 typmod
)
92 char *res
= (char *) palloc(64);
93 const char *tz
= istz
? " with time zone" : " without time zone";
96 snprintf(res
, 64, "(%d)%s", (int) typmod
, tz
);
98 snprintf(res
, 64, "%s", tz
);
103 /*****************************************************************************
105 *****************************************************************************/
109 * Given date text string, convert to internal date format.
112 date_in(PG_FUNCTION_ARGS
)
114 char *str
= PG_GETARG_CSTRING(0);
123 char *field
[MAXDATEFIELDS
];
124 int ftype
[MAXDATEFIELDS
];
125 char workbuf
[MAXDATELEN
+ 1];
127 dterr
= ParseDateTime(str
, workbuf
, sizeof(workbuf
),
128 field
, ftype
, MAXDATEFIELDS
, &nf
);
130 dterr
= DecodeDateTime(field
, ftype
, nf
, &dtype
, tm
, &fsec
, &tzp
);
132 DateTimeParseError(dterr
, str
, "date");
141 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
142 errmsg("date/time value \"current\" is no longer supported")));
144 GetCurrentDateTime(tm
);
153 PG_RETURN_DATEADT(date
);
157 PG_RETURN_DATEADT(date
);
160 DateTimeParseError(DTERR_BAD_FORMAT
, str
, "date");
164 if (!IS_VALID_JULIAN(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
))
166 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
167 errmsg("date out of range: \"%s\"", str
)));
169 date
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - POSTGRES_EPOCH_JDATE
;
171 PG_RETURN_DATEADT(date
);
175 * Given internal format date, convert to text string.
178 date_out(PG_FUNCTION_ARGS
)
180 DateADT date
= PG_GETARG_DATEADT(0);
184 char buf
[MAXDATELEN
+ 1];
186 if (DATE_NOT_FINITE(date
))
187 EncodeSpecialDate(date
, buf
);
190 j2date(date
+ POSTGRES_EPOCH_JDATE
,
191 &(tm
->tm_year
), &(tm
->tm_mon
), &(tm
->tm_mday
));
192 EncodeDateOnly(tm
, DateStyle
, buf
);
195 result
= pstrdup(buf
);
196 PG_RETURN_CSTRING(result
);
200 * date_recv - converts external binary format to date
203 date_recv(PG_FUNCTION_ARGS
)
205 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
207 PG_RETURN_DATEADT((DateADT
) pq_getmsgint(buf
, sizeof(DateADT
)));
211 * date_send - converts date to binary format
214 date_send(PG_FUNCTION_ARGS
)
216 DateADT date
= PG_GETARG_DATEADT(0);
219 pq_begintypsend(&buf
);
220 pq_sendint(&buf
, date
, sizeof(date
));
221 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
225 * Convert reserved date values to string.
228 EncodeSpecialDate(DateADT dt
, char *str
)
230 if (DATE_IS_NOBEGIN(dt
))
232 else if (DATE_IS_NOEND(dt
))
234 else /* shouldn't happen */
235 elog(ERROR
, "invalid argument for EncodeSpecialDate");
240 * Comparison functions for dates
244 date_eq(PG_FUNCTION_ARGS
)
246 DateADT dateVal1
= PG_GETARG_DATEADT(0);
247 DateADT dateVal2
= PG_GETARG_DATEADT(1);
249 PG_RETURN_BOOL(dateVal1
== dateVal2
);
253 date_ne(PG_FUNCTION_ARGS
)
255 DateADT dateVal1
= PG_GETARG_DATEADT(0);
256 DateADT dateVal2
= PG_GETARG_DATEADT(1);
258 PG_RETURN_BOOL(dateVal1
!= dateVal2
);
262 date_lt(PG_FUNCTION_ARGS
)
264 DateADT dateVal1
= PG_GETARG_DATEADT(0);
265 DateADT dateVal2
= PG_GETARG_DATEADT(1);
267 PG_RETURN_BOOL(dateVal1
< dateVal2
);
271 date_le(PG_FUNCTION_ARGS
)
273 DateADT dateVal1
= PG_GETARG_DATEADT(0);
274 DateADT dateVal2
= PG_GETARG_DATEADT(1);
276 PG_RETURN_BOOL(dateVal1
<= dateVal2
);
280 date_gt(PG_FUNCTION_ARGS
)
282 DateADT dateVal1
= PG_GETARG_DATEADT(0);
283 DateADT dateVal2
= PG_GETARG_DATEADT(1);
285 PG_RETURN_BOOL(dateVal1
> dateVal2
);
289 date_ge(PG_FUNCTION_ARGS
)
291 DateADT dateVal1
= PG_GETARG_DATEADT(0);
292 DateADT dateVal2
= PG_GETARG_DATEADT(1);
294 PG_RETURN_BOOL(dateVal1
>= dateVal2
);
298 date_cmp(PG_FUNCTION_ARGS
)
300 DateADT dateVal1
= PG_GETARG_DATEADT(0);
301 DateADT dateVal2
= PG_GETARG_DATEADT(1);
303 if (dateVal1
< dateVal2
)
305 else if (dateVal1
> dateVal2
)
311 date_finite(PG_FUNCTION_ARGS
)
313 DateADT date
= PG_GETARG_DATEADT(0);
315 PG_RETURN_BOOL(!DATE_NOT_FINITE(date
));
319 date_larger(PG_FUNCTION_ARGS
)
321 DateADT dateVal1
= PG_GETARG_DATEADT(0);
322 DateADT dateVal2
= PG_GETARG_DATEADT(1);
324 PG_RETURN_DATEADT((dateVal1
> dateVal2
) ? dateVal1
: dateVal2
);
328 date_smaller(PG_FUNCTION_ARGS
)
330 DateADT dateVal1
= PG_GETARG_DATEADT(0);
331 DateADT dateVal2
= PG_GETARG_DATEADT(1);
333 PG_RETURN_DATEADT((dateVal1
< dateVal2
) ? dateVal1
: dateVal2
);
336 /* Compute difference between two dates in days.
339 date_mi(PG_FUNCTION_ARGS
)
341 DateADT dateVal1
= PG_GETARG_DATEADT(0);
342 DateADT dateVal2
= PG_GETARG_DATEADT(1);
344 if (DATE_NOT_FINITE(dateVal1
) || DATE_NOT_FINITE(dateVal2
))
346 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
347 errmsg("cannot subtract infinite dates")));
349 PG_RETURN_INT32((int32
) (dateVal1
- dateVal2
));
352 /* Add a number of days to a date, giving a new date.
353 * Must handle both positive and negative numbers of days.
356 date_pli(PG_FUNCTION_ARGS
)
358 DateADT dateVal
= PG_GETARG_DATEADT(0);
359 int32 days
= PG_GETARG_INT32(1);
361 if (DATE_NOT_FINITE(dateVal
))
362 days
= 0; /* can't change infinity */
364 PG_RETURN_DATEADT(dateVal
+ days
);
367 /* Subtract a number of days from a date, giving a new date.
370 date_mii(PG_FUNCTION_ARGS
)
372 DateADT dateVal
= PG_GETARG_DATEADT(0);
373 int32 days
= PG_GETARG_INT32(1);
375 if (DATE_NOT_FINITE(dateVal
))
376 days
= 0; /* can't change infinity */
378 PG_RETURN_DATEADT(dateVal
- days
);
382 * Internal routines for promoting date to timestamp and timestamp with
387 date2timestamp(DateADT dateVal
)
391 if (DATE_IS_NOBEGIN(dateVal
))
392 TIMESTAMP_NOBEGIN(result
);
393 else if (DATE_IS_NOEND(dateVal
))
394 TIMESTAMP_NOEND(result
);
397 #ifdef HAVE_INT64_TIMESTAMP
398 /* date is days since 2000, timestamp is microseconds since same... */
399 result
= dateVal
* USECS_PER_DAY
;
400 /* Date's range is wider than timestamp's, so check for overflow */
401 if (result
/ USECS_PER_DAY
!= dateVal
)
403 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
404 errmsg("date out of range for timestamp")));
406 /* date is days since 2000, timestamp is seconds since same... */
407 result
= dateVal
* (double) SECS_PER_DAY
;
415 date2timestamptz(DateADT dateVal
)
422 if (DATE_IS_NOBEGIN(dateVal
))
423 TIMESTAMP_NOBEGIN(result
);
424 else if (DATE_IS_NOEND(dateVal
))
425 TIMESTAMP_NOEND(result
);
428 j2date(dateVal
+ POSTGRES_EPOCH_JDATE
,
429 &(tm
->tm_year
), &(tm
->tm_mon
), &(tm
->tm_mday
));
433 tz
= DetermineTimeZoneOffset(tm
, session_timezone
);
435 #ifdef HAVE_INT64_TIMESTAMP
436 result
= dateVal
* USECS_PER_DAY
+ tz
* USECS_PER_SEC
;
437 /* Date's range is wider than timestamp's, so check for overflow */
438 if ((result
- tz
* USECS_PER_SEC
) / USECS_PER_DAY
!= dateVal
)
440 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
441 errmsg("date out of range for timestamp")));
443 result
= dateVal
* (double) SECS_PER_DAY
+ tz
;
452 * Crosstype comparison functions for dates
456 date_eq_timestamp(PG_FUNCTION_ARGS
)
458 DateADT dateVal
= PG_GETARG_DATEADT(0);
459 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
462 dt1
= date2timestamp(dateVal
);
464 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) == 0);
468 date_ne_timestamp(PG_FUNCTION_ARGS
)
470 DateADT dateVal
= PG_GETARG_DATEADT(0);
471 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
474 dt1
= date2timestamp(dateVal
);
476 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) != 0);
480 date_lt_timestamp(PG_FUNCTION_ARGS
)
482 DateADT dateVal
= PG_GETARG_DATEADT(0);
483 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
486 dt1
= date2timestamp(dateVal
);
488 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) < 0);
492 date_gt_timestamp(PG_FUNCTION_ARGS
)
494 DateADT dateVal
= PG_GETARG_DATEADT(0);
495 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
498 dt1
= date2timestamp(dateVal
);
500 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) > 0);
504 date_le_timestamp(PG_FUNCTION_ARGS
)
506 DateADT dateVal
= PG_GETARG_DATEADT(0);
507 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
510 dt1
= date2timestamp(dateVal
);
512 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) <= 0);
516 date_ge_timestamp(PG_FUNCTION_ARGS
)
518 DateADT dateVal
= PG_GETARG_DATEADT(0);
519 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
522 dt1
= date2timestamp(dateVal
);
524 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) >= 0);
528 date_cmp_timestamp(PG_FUNCTION_ARGS
)
530 DateADT dateVal
= PG_GETARG_DATEADT(0);
531 Timestamp dt2
= PG_GETARG_TIMESTAMP(1);
534 dt1
= date2timestamp(dateVal
);
536 PG_RETURN_INT32(timestamp_cmp_internal(dt1
, dt2
));
540 date_eq_timestamptz(PG_FUNCTION_ARGS
)
542 DateADT dateVal
= PG_GETARG_DATEADT(0);
543 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
546 dt1
= date2timestamptz(dateVal
);
548 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) == 0);
552 date_ne_timestamptz(PG_FUNCTION_ARGS
)
554 DateADT dateVal
= PG_GETARG_DATEADT(0);
555 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
558 dt1
= date2timestamptz(dateVal
);
560 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) != 0);
564 date_lt_timestamptz(PG_FUNCTION_ARGS
)
566 DateADT dateVal
= PG_GETARG_DATEADT(0);
567 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
570 dt1
= date2timestamptz(dateVal
);
572 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) < 0);
576 date_gt_timestamptz(PG_FUNCTION_ARGS
)
578 DateADT dateVal
= PG_GETARG_DATEADT(0);
579 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
582 dt1
= date2timestamptz(dateVal
);
584 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) > 0);
588 date_le_timestamptz(PG_FUNCTION_ARGS
)
590 DateADT dateVal
= PG_GETARG_DATEADT(0);
591 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
594 dt1
= date2timestamptz(dateVal
);
596 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) <= 0);
600 date_ge_timestamptz(PG_FUNCTION_ARGS
)
602 DateADT dateVal
= PG_GETARG_DATEADT(0);
603 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
606 dt1
= date2timestamptz(dateVal
);
608 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) >= 0);
612 date_cmp_timestamptz(PG_FUNCTION_ARGS
)
614 DateADT dateVal
= PG_GETARG_DATEADT(0);
615 TimestampTz dt2
= PG_GETARG_TIMESTAMPTZ(1);
618 dt1
= date2timestamptz(dateVal
);
620 PG_RETURN_INT32(timestamptz_cmp_internal(dt1
, dt2
));
624 timestamp_eq_date(PG_FUNCTION_ARGS
)
626 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
627 DateADT dateVal
= PG_GETARG_DATEADT(1);
630 dt2
= date2timestamp(dateVal
);
632 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) == 0);
636 timestamp_ne_date(PG_FUNCTION_ARGS
)
638 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
639 DateADT dateVal
= PG_GETARG_DATEADT(1);
642 dt2
= date2timestamp(dateVal
);
644 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) != 0);
648 timestamp_lt_date(PG_FUNCTION_ARGS
)
650 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
651 DateADT dateVal
= PG_GETARG_DATEADT(1);
654 dt2
= date2timestamp(dateVal
);
656 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) < 0);
660 timestamp_gt_date(PG_FUNCTION_ARGS
)
662 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
663 DateADT dateVal
= PG_GETARG_DATEADT(1);
666 dt2
= date2timestamp(dateVal
);
668 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) > 0);
672 timestamp_le_date(PG_FUNCTION_ARGS
)
674 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
675 DateADT dateVal
= PG_GETARG_DATEADT(1);
678 dt2
= date2timestamp(dateVal
);
680 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) <= 0);
684 timestamp_ge_date(PG_FUNCTION_ARGS
)
686 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
687 DateADT dateVal
= PG_GETARG_DATEADT(1);
690 dt2
= date2timestamp(dateVal
);
692 PG_RETURN_BOOL(timestamp_cmp_internal(dt1
, dt2
) >= 0);
696 timestamp_cmp_date(PG_FUNCTION_ARGS
)
698 Timestamp dt1
= PG_GETARG_TIMESTAMP(0);
699 DateADT dateVal
= PG_GETARG_DATEADT(1);
702 dt2
= date2timestamp(dateVal
);
704 PG_RETURN_INT32(timestamp_cmp_internal(dt1
, dt2
));
708 timestamptz_eq_date(PG_FUNCTION_ARGS
)
710 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
711 DateADT dateVal
= PG_GETARG_DATEADT(1);
714 dt2
= date2timestamptz(dateVal
);
716 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) == 0);
720 timestamptz_ne_date(PG_FUNCTION_ARGS
)
722 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
723 DateADT dateVal
= PG_GETARG_DATEADT(1);
726 dt2
= date2timestamptz(dateVal
);
728 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) != 0);
732 timestamptz_lt_date(PG_FUNCTION_ARGS
)
734 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
735 DateADT dateVal
= PG_GETARG_DATEADT(1);
738 dt2
= date2timestamptz(dateVal
);
740 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) < 0);
744 timestamptz_gt_date(PG_FUNCTION_ARGS
)
746 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
747 DateADT dateVal
= PG_GETARG_DATEADT(1);
750 dt2
= date2timestamptz(dateVal
);
752 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) > 0);
756 timestamptz_le_date(PG_FUNCTION_ARGS
)
758 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
759 DateADT dateVal
= PG_GETARG_DATEADT(1);
762 dt2
= date2timestamptz(dateVal
);
764 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) <= 0);
768 timestamptz_ge_date(PG_FUNCTION_ARGS
)
770 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
771 DateADT dateVal
= PG_GETARG_DATEADT(1);
774 dt2
= date2timestamptz(dateVal
);
776 PG_RETURN_BOOL(timestamptz_cmp_internal(dt1
, dt2
) >= 0);
780 timestamptz_cmp_date(PG_FUNCTION_ARGS
)
782 TimestampTz dt1
= PG_GETARG_TIMESTAMPTZ(0);
783 DateADT dateVal
= PG_GETARG_DATEADT(1);
786 dt2
= date2timestamptz(dateVal
);
788 PG_RETURN_INT32(timestamptz_cmp_internal(dt1
, dt2
));
792 /* Add an interval to a date, giving a new date.
793 * Must handle both positive and negative intervals.
795 * We implement this by promoting the date to timestamp (without time zone)
796 * and then using the timestamp plus interval function.
799 date_pl_interval(PG_FUNCTION_ARGS
)
801 DateADT dateVal
= PG_GETARG_DATEADT(0);
802 Interval
*span
= PG_GETARG_INTERVAL_P(1);
805 dateStamp
= date2timestamp(dateVal
);
807 return DirectFunctionCall2(timestamp_pl_interval
,
808 TimestampGetDatum(dateStamp
),
809 PointerGetDatum(span
));
812 /* Subtract an interval from a date, giving a new date.
813 * Must handle both positive and negative intervals.
815 * We implement this by promoting the date to timestamp (without time zone)
816 * and then using the timestamp minus interval function.
819 date_mi_interval(PG_FUNCTION_ARGS
)
821 DateADT dateVal
= PG_GETARG_DATEADT(0);
822 Interval
*span
= PG_GETARG_INTERVAL_P(1);
825 dateStamp
= date2timestamp(dateVal
);
827 return DirectFunctionCall2(timestamp_mi_interval
,
828 TimestampGetDatum(dateStamp
),
829 PointerGetDatum(span
));
833 * Convert date to timestamp data type.
836 date_timestamp(PG_FUNCTION_ARGS
)
838 DateADT dateVal
= PG_GETARG_DATEADT(0);
841 result
= date2timestamp(dateVal
);
843 PG_RETURN_TIMESTAMP(result
);
848 * Convert timestamp to date data type.
851 timestamp_date(PG_FUNCTION_ARGS
)
853 Timestamp timestamp
= PG_GETARG_TIMESTAMP(0);
859 if (TIMESTAMP_IS_NOBEGIN(timestamp
))
860 DATE_NOBEGIN(result
);
861 else if (TIMESTAMP_IS_NOEND(timestamp
))
865 if (timestamp2tm(timestamp
, NULL
, tm
, &fsec
, NULL
, NULL
) != 0)
867 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
868 errmsg("timestamp out of range")));
870 result
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - POSTGRES_EPOCH_JDATE
;
873 PG_RETURN_DATEADT(result
);
877 /* date_timestamptz()
878 * Convert date to timestamp with time zone data type.
881 date_timestamptz(PG_FUNCTION_ARGS
)
883 DateADT dateVal
= PG_GETARG_DATEADT(0);
886 result
= date2timestamptz(dateVal
);
888 PG_RETURN_TIMESTAMP(result
);
892 /* timestamptz_date()
893 * Convert timestamp with time zone to date data type.
896 timestamptz_date(PG_FUNCTION_ARGS
)
898 TimestampTz timestamp
= PG_GETARG_TIMESTAMP(0);
906 if (TIMESTAMP_IS_NOBEGIN(timestamp
))
907 DATE_NOBEGIN(result
);
908 else if (TIMESTAMP_IS_NOEND(timestamp
))
912 if (timestamp2tm(timestamp
, &tz
, tm
, &fsec
, &tzn
, NULL
) != 0)
914 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
915 errmsg("timestamp out of range")));
917 result
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - POSTGRES_EPOCH_JDATE
;
920 PG_RETURN_DATEADT(result
);
925 * Convert abstime to date data type.
928 abstime_date(PG_FUNCTION_ARGS
)
930 AbsoluteTime abstime
= PG_GETARG_ABSOLUTETIME(0);
938 case INVALID_ABSTIME
:
940 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
941 errmsg("cannot convert reserved abstime value to date")));
942 result
= 0; /* keep compiler quiet */
945 case NOSTART_ABSTIME
:
946 DATE_NOBEGIN(result
);
954 abstime2tm(abstime
, &tz
, tm
, NULL
);
955 result
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - POSTGRES_EPOCH_JDATE
;
959 PG_RETURN_DATEADT(result
);
963 /*****************************************************************************
965 *****************************************************************************/
968 time_in(PG_FUNCTION_ARGS
)
970 char *str
= PG_GETARG_CSTRING(0);
973 Oid typelem
= PG_GETARG_OID(1);
975 int32 typmod
= PG_GETARG_INT32(2);
983 char workbuf
[MAXDATELEN
+ 1];
984 char *field
[MAXDATEFIELDS
];
986 int ftype
[MAXDATEFIELDS
];
988 dterr
= ParseDateTime(str
, workbuf
, sizeof(workbuf
),
989 field
, ftype
, MAXDATEFIELDS
, &nf
);
991 dterr
= DecodeTimeOnly(field
, ftype
, nf
, &dtype
, tm
, &fsec
, &tz
);
993 DateTimeParseError(dterr
, str
, "time");
995 tm2time(tm
, fsec
, &result
);
996 AdjustTimeForTypmod(&result
, typmod
);
998 PG_RETURN_TIMEADT(result
);
1002 * Convert a tm structure to a time data type.
1005 tm2time(struct pg_tm
* tm
, fsec_t fsec
, TimeADT
*result
)
1007 #ifdef HAVE_INT64_TIMESTAMP
1008 *result
= ((((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
)
1009 * USECS_PER_SEC
) + fsec
;
1011 *result
= ((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
+ fsec
;
1017 * Convert time data type to POSIX time structure.
1019 * For dates within the range of pg_time_t, convert to the local time zone.
1020 * If out of this range, leave as UTC (in practice that could only happen
1021 * if pg_time_t is just 32 bits) - thomas 97/05/27
1024 time2tm(TimeADT time
, struct pg_tm
* tm
, fsec_t
*fsec
)
1026 #ifdef HAVE_INT64_TIMESTAMP
1027 tm
->tm_hour
= time
/ USECS_PER_HOUR
;
1028 time
-= tm
->tm_hour
* USECS_PER_HOUR
;
1029 tm
->tm_min
= time
/ USECS_PER_MINUTE
;
1030 time
-= tm
->tm_min
* USECS_PER_MINUTE
;
1031 tm
->tm_sec
= time
/ USECS_PER_SEC
;
1032 time
-= tm
->tm_sec
* USECS_PER_SEC
;
1039 TMODULO(trem
, tm
->tm_hour
, (double) SECS_PER_HOUR
);
1040 TMODULO(trem
, tm
->tm_min
, (double) SECS_PER_MINUTE
);
1041 TMODULO(trem
, tm
->tm_sec
, 1.0);
1042 trem
= TIMEROUND(trem
);
1043 /* roundoff may need to propagate to higher-order fields */
1056 time_out(PG_FUNCTION_ARGS
)
1058 TimeADT time
= PG_GETARG_TIMEADT(0);
1063 char buf
[MAXDATELEN
+ 1];
1065 time2tm(time
, tm
, &fsec
);
1066 EncodeTimeOnly(tm
, fsec
, NULL
, DateStyle
, buf
);
1068 result
= pstrdup(buf
);
1069 PG_RETURN_CSTRING(result
);
1073 * time_recv - converts external binary format to time
1075 * We make no attempt to provide compatibility between int and float
1076 * time representations ...
1079 time_recv(PG_FUNCTION_ARGS
)
1081 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
1084 Oid typelem
= PG_GETARG_OID(1);
1086 int32 typmod
= PG_GETARG_INT32(2);
1089 #ifdef HAVE_INT64_TIMESTAMP
1090 result
= pq_getmsgint64(buf
);
1092 if (result
< INT64CONST(0) || result
> USECS_PER_DAY
)
1094 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1095 errmsg("time out of range")));
1097 result
= pq_getmsgfloat8(buf
);
1099 if (result
< 0 || result
> (double) SECS_PER_DAY
)
1101 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1102 errmsg("time out of range")));
1105 AdjustTimeForTypmod(&result
, typmod
);
1107 PG_RETURN_TIMEADT(result
);
1111 * time_send - converts time to binary format
1114 time_send(PG_FUNCTION_ARGS
)
1116 TimeADT time
= PG_GETARG_TIMEADT(0);
1119 pq_begintypsend(&buf
);
1120 #ifdef HAVE_INT64_TIMESTAMP
1121 pq_sendint64(&buf
, time
);
1123 pq_sendfloat8(&buf
, time
);
1125 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
1129 timetypmodin(PG_FUNCTION_ARGS
)
1131 ArrayType
*ta
= PG_GETARG_ARRAYTYPE_P(0);
1133 PG_RETURN_INT32(anytime_typmodin(false, ta
));
1137 timetypmodout(PG_FUNCTION_ARGS
)
1139 int32 typmod
= PG_GETARG_INT32(0);
1141 PG_RETURN_CSTRING(anytime_typmodout(false, typmod
));
1146 * Adjust time type for specified scale factor.
1147 * Used by PostgreSQL type system to stuff columns.
1150 time_scale(PG_FUNCTION_ARGS
)
1152 TimeADT time
= PG_GETARG_TIMEADT(0);
1153 int32 typmod
= PG_GETARG_INT32(1);
1157 AdjustTimeForTypmod(&result
, typmod
);
1159 PG_RETURN_TIMEADT(result
);
1162 /* AdjustTimeForTypmod()
1163 * Force the precision of the time value to a specified value.
1164 * Uses *exactly* the same code as in AdjustTimestampForTypemod()
1165 * but we make a separate copy because those types do not
1166 * have a fundamental tie together but rather a coincidence of
1167 * implementation. - thomas
1170 AdjustTimeForTypmod(TimeADT
*time
, int32 typmod
)
1172 #ifdef HAVE_INT64_TIMESTAMP
1173 static const int64 TimeScales
[MAX_TIME_PRECISION
+ 1] = {
1174 INT64CONST(1000000),
1183 static const int64 TimeOffsets
[MAX_TIME_PRECISION
+ 1] = {
1193 /* note MAX_TIME_PRECISION differs in this case */
1194 static const double TimeScales
[MAX_TIME_PRECISION
+ 1] = {
1209 if (typmod
>= 0 && typmod
<= MAX_TIME_PRECISION
)
1212 * Note: this round-to-nearest code is not completely consistent about
1213 * rounding values that are exactly halfway between integral values.
1214 * On most platforms, rint() will implement round-to-nearest-even, but
1215 * the integer code always rounds up (away from zero). Is it worth
1216 * trying to be consistent?
1218 #ifdef HAVE_INT64_TIMESTAMP
1219 if (*time
>= INT64CONST(0))
1220 *time
= ((*time
+ TimeOffsets
[typmod
]) / TimeScales
[typmod
]) *
1223 *time
= -((((-*time
) + TimeOffsets
[typmod
]) / TimeScales
[typmod
]) *
1224 TimeScales
[typmod
]);
1226 *time
= rint((double) *time
* TimeScales
[typmod
]) / TimeScales
[typmod
];
1233 time_eq(PG_FUNCTION_ARGS
)
1235 TimeADT time1
= PG_GETARG_TIMEADT(0);
1236 TimeADT time2
= PG_GETARG_TIMEADT(1);
1238 PG_RETURN_BOOL(time1
== time2
);
1242 time_ne(PG_FUNCTION_ARGS
)
1244 TimeADT time1
= PG_GETARG_TIMEADT(0);
1245 TimeADT time2
= PG_GETARG_TIMEADT(1);
1247 PG_RETURN_BOOL(time1
!= time2
);
1251 time_lt(PG_FUNCTION_ARGS
)
1253 TimeADT time1
= PG_GETARG_TIMEADT(0);
1254 TimeADT time2
= PG_GETARG_TIMEADT(1);
1256 PG_RETURN_BOOL(time1
< time2
);
1260 time_le(PG_FUNCTION_ARGS
)
1262 TimeADT time1
= PG_GETARG_TIMEADT(0);
1263 TimeADT time2
= PG_GETARG_TIMEADT(1);
1265 PG_RETURN_BOOL(time1
<= time2
);
1269 time_gt(PG_FUNCTION_ARGS
)
1271 TimeADT time1
= PG_GETARG_TIMEADT(0);
1272 TimeADT time2
= PG_GETARG_TIMEADT(1);
1274 PG_RETURN_BOOL(time1
> time2
);
1278 time_ge(PG_FUNCTION_ARGS
)
1280 TimeADT time1
= PG_GETARG_TIMEADT(0);
1281 TimeADT time2
= PG_GETARG_TIMEADT(1);
1283 PG_RETURN_BOOL(time1
>= time2
);
1287 time_cmp(PG_FUNCTION_ARGS
)
1289 TimeADT time1
= PG_GETARG_TIMEADT(0);
1290 TimeADT time2
= PG_GETARG_TIMEADT(1);
1293 PG_RETURN_INT32(-1);
1300 time_hash(PG_FUNCTION_ARGS
)
1302 /* We can use either hashint8 or hashfloat8 directly */
1303 #ifdef HAVE_INT64_TIMESTAMP
1304 return hashint8(fcinfo
);
1306 return hashfloat8(fcinfo
);
1311 time_larger(PG_FUNCTION_ARGS
)
1313 TimeADT time1
= PG_GETARG_TIMEADT(0);
1314 TimeADT time2
= PG_GETARG_TIMEADT(1);
1316 PG_RETURN_TIMEADT((time1
> time2
) ? time1
: time2
);
1320 time_smaller(PG_FUNCTION_ARGS
)
1322 TimeADT time1
= PG_GETARG_TIMEADT(0);
1323 TimeADT time2
= PG_GETARG_TIMEADT(1);
1325 PG_RETURN_TIMEADT((time1
< time2
) ? time1
: time2
);
1328 /* overlaps_time() --- implements the SQL92 OVERLAPS operator.
1330 * Algorithm is per SQL92 spec. This is much harder than you'd think
1331 * because the spec requires us to deliver a non-null answer in some cases
1332 * where some of the inputs are null.
1335 overlaps_time(PG_FUNCTION_ARGS
)
1338 * The arguments are TimeADT, but we leave them as generic Datums to avoid
1339 * dereferencing nulls (TimeADT is pass-by-reference!)
1341 Datum ts1
= PG_GETARG_DATUM(0);
1342 Datum te1
= PG_GETARG_DATUM(1);
1343 Datum ts2
= PG_GETARG_DATUM(2);
1344 Datum te2
= PG_GETARG_DATUM(3);
1345 bool ts1IsNull
= PG_ARGISNULL(0);
1346 bool te1IsNull
= PG_ARGISNULL(1);
1347 bool ts2IsNull
= PG_ARGISNULL(2);
1348 bool te2IsNull
= PG_ARGISNULL(3);
1350 #define TIMEADT_GT(t1,t2) \
1351 (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1352 #define TIMEADT_LT(t1,t2) \
1353 (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1356 * If both endpoints of interval 1 are null, the result is null (unknown).
1357 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1358 * take ts1 as the lesser endpoint.
1364 /* swap null for non-null */
1368 else if (!te1IsNull
)
1370 if (TIMEADT_GT(ts1
, te1
))
1379 /* Likewise for interval 2. */
1384 /* swap null for non-null */
1388 else if (!te2IsNull
)
1390 if (TIMEADT_GT(ts2
, te2
))
1400 * At this point neither ts1 nor ts2 is null, so we can consider three
1401 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1403 if (TIMEADT_GT(ts1
, ts2
))
1406 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1407 * in the presence of nulls it's not quite completely so.
1411 if (TIMEADT_LT(ts1
, te2
))
1412 PG_RETURN_BOOL(true);
1417 * If te1 is not null then we had ts1 <= te1 above, and we just found
1418 * ts1 >= te2, hence te1 >= te2.
1420 PG_RETURN_BOOL(false);
1422 else if (TIMEADT_LT(ts1
, ts2
))
1424 /* This case is ts2 < te1 OR te2 < te1 */
1427 if (TIMEADT_LT(ts2
, te1
))
1428 PG_RETURN_BOOL(true);
1433 * If te2 is not null then we had ts2 <= te2 above, and we just found
1434 * ts2 >= te1, hence te2 >= te1.
1436 PG_RETURN_BOOL(false);
1441 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1442 * rather silly way of saying "true if both are nonnull, else null".
1444 if (te1IsNull
|| te2IsNull
)
1446 PG_RETURN_BOOL(true);
1454 * Convert timestamp to time data type.
1457 timestamp_time(PG_FUNCTION_ARGS
)
1459 Timestamp timestamp
= PG_GETARG_TIMESTAMP(0);
1465 if (TIMESTAMP_NOT_FINITE(timestamp
))
1468 if (timestamp2tm(timestamp
, NULL
, tm
, &fsec
, NULL
, NULL
) != 0)
1470 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1471 errmsg("timestamp out of range")));
1473 #ifdef HAVE_INT64_TIMESTAMP
1476 * Could also do this with time = (timestamp / USECS_PER_DAY *
1477 * USECS_PER_DAY) - timestamp;
1479 result
= ((((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
) *
1480 USECS_PER_SEC
) + fsec
;
1482 result
= ((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
+ fsec
;
1485 PG_RETURN_TIMEADT(result
);
1488 /* timestamptz_time()
1489 * Convert timestamptz to time data type.
1492 timestamptz_time(PG_FUNCTION_ARGS
)
1494 TimestampTz timestamp
= PG_GETARG_TIMESTAMP(0);
1502 if (TIMESTAMP_NOT_FINITE(timestamp
))
1505 if (timestamp2tm(timestamp
, &tz
, tm
, &fsec
, &tzn
, NULL
) != 0)
1507 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1508 errmsg("timestamp out of range")));
1510 #ifdef HAVE_INT64_TIMESTAMP
1513 * Could also do this with time = (timestamp / USECS_PER_DAY *
1514 * USECS_PER_DAY) - timestamp;
1516 result
= ((((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
) *
1517 USECS_PER_SEC
) + fsec
;
1519 result
= ((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
+ fsec
;
1522 PG_RETURN_TIMEADT(result
);
1525 /* datetime_timestamp()
1526 * Convert date and time to timestamp data type.
1529 datetime_timestamp(PG_FUNCTION_ARGS
)
1531 DateADT date
= PG_GETARG_DATEADT(0);
1532 TimeADT time
= PG_GETARG_TIMEADT(1);
1535 result
= date2timestamp(date
);
1536 if (!TIMESTAMP_NOT_FINITE(result
))
1539 PG_RETURN_TIMESTAMP(result
);
1543 * Convert time to interval data type.
1546 time_interval(PG_FUNCTION_ARGS
)
1548 TimeADT time
= PG_GETARG_TIMEADT(0);
1551 result
= (Interval
*) palloc(sizeof(Interval
));
1553 result
->time
= time
;
1557 PG_RETURN_INTERVAL_P(result
);
1561 * Convert interval to time data type.
1563 * This is defined as producing the fractional-day portion of the interval.
1564 * Therefore, we can just ignore the months field. It is not real clear
1565 * what to do with negative intervals, but we choose to subtract the floor,
1566 * so that, say, '-2 hours' becomes '22:00:00'.
1569 interval_time(PG_FUNCTION_ARGS
)
1571 Interval
*span
= PG_GETARG_INTERVAL_P(0);
1574 #ifdef HAVE_INT64_TIMESTAMP
1577 result
= span
->time
;
1578 if (result
>= USECS_PER_DAY
)
1580 days
= result
/ USECS_PER_DAY
;
1581 result
-= days
* USECS_PER_DAY
;
1583 else if (result
< 0)
1585 days
= (-result
+ USECS_PER_DAY
- 1) / USECS_PER_DAY
;
1586 result
+= days
* USECS_PER_DAY
;
1589 result
= span
->time
;
1590 if (result
>= (double) SECS_PER_DAY
|| result
< 0)
1591 result
-= floor(result
/ (double) SECS_PER_DAY
) * (double) SECS_PER_DAY
;
1594 PG_RETURN_TIMEADT(result
);
1598 * Subtract two times to produce an interval.
1601 time_mi_time(PG_FUNCTION_ARGS
)
1603 TimeADT time1
= PG_GETARG_TIMEADT(0);
1604 TimeADT time2
= PG_GETARG_TIMEADT(1);
1607 result
= (Interval
*) palloc(sizeof(Interval
));
1611 result
->time
= time1
- time2
;
1613 PG_RETURN_INTERVAL_P(result
);
1616 /* time_pl_interval()
1617 * Add interval to time.
1620 time_pl_interval(PG_FUNCTION_ARGS
)
1622 TimeADT time
= PG_GETARG_TIMEADT(0);
1623 Interval
*span
= PG_GETARG_INTERVAL_P(1);
1626 #ifdef HAVE_INT64_TIMESTAMP
1627 result
= time
+ span
->time
;
1628 result
-= result
/ USECS_PER_DAY
* USECS_PER_DAY
;
1629 if (result
< INT64CONST(0))
1630 result
+= USECS_PER_DAY
;
1634 result
= time
+ span
->time
;
1635 TMODULO(result
, time1
, (double) SECS_PER_DAY
);
1637 result
+= SECS_PER_DAY
;
1640 PG_RETURN_TIMEADT(result
);
1643 /* time_mi_interval()
1644 * Subtract interval from time.
1647 time_mi_interval(PG_FUNCTION_ARGS
)
1649 TimeADT time
= PG_GETARG_TIMEADT(0);
1650 Interval
*span
= PG_GETARG_INTERVAL_P(1);
1653 #ifdef HAVE_INT64_TIMESTAMP
1654 result
= time
- span
->time
;
1655 result
-= result
/ USECS_PER_DAY
* USECS_PER_DAY
;
1656 if (result
< INT64CONST(0))
1657 result
+= USECS_PER_DAY
;
1661 result
= time
- span
->time
;
1662 TMODULO(result
, time1
, (double) SECS_PER_DAY
);
1664 result
+= SECS_PER_DAY
;
1667 PG_RETURN_TIMEADT(result
);
1672 * Extract specified field from time type.
1675 time_part(PG_FUNCTION_ARGS
)
1677 text
*units
= PG_GETARG_TEXT_PP(0);
1678 TimeADT time
= PG_GETARG_TIMEADT(1);
1684 lowunits
= downcase_truncate_identifier(VARDATA_ANY(units
),
1685 VARSIZE_ANY_EXHDR(units
),
1688 type
= DecodeUnits(0, lowunits
, &val
);
1689 if (type
== UNKNOWN_FIELD
)
1690 type
= DecodeSpecial(0, lowunits
, &val
);
1698 time2tm(time
, tm
, &fsec
);
1703 #ifdef HAVE_INT64_TIMESTAMP
1704 result
= tm
->tm_sec
* USECS_PER_SEC
+ fsec
;
1706 result
= (tm
->tm_sec
+ fsec
) * 1000000;
1711 #ifdef HAVE_INT64_TIMESTAMP
1712 result
= tm
->tm_sec
* INT64CONST(1000) + fsec
/ INT64CONST(1000);
1714 result
= (tm
->tm_sec
+ fsec
) * 1000;
1719 #ifdef HAVE_INT64_TIMESTAMP
1720 result
= tm
->tm_sec
+ fsec
/ USECS_PER_SEC
;
1722 result
= tm
->tm_sec
+ fsec
;
1727 result
= tm
->tm_min
;
1731 result
= tm
->tm_hour
;
1743 case DTK_MILLENNIUM
:
1747 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1748 errmsg("\"time\" units \"%s\" not recognized",
1753 else if (type
== RESERV
&& val
== DTK_EPOCH
)
1755 #ifdef HAVE_INT64_TIMESTAMP
1756 result
= time
/ 1000000.0;
1764 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1765 errmsg("\"time\" units \"%s\" not recognized",
1770 PG_RETURN_FLOAT8(result
);
1774 /*****************************************************************************
1775 * Time With Time Zone ADT
1776 *****************************************************************************/
1779 * Convert a tm structure to a time data type.
1782 tm2timetz(struct pg_tm
* tm
, fsec_t fsec
, int tz
, TimeTzADT
*result
)
1784 #ifdef HAVE_INT64_TIMESTAMP
1785 result
->time
= ((((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
) *
1786 USECS_PER_SEC
) + fsec
;
1788 result
->time
= ((tm
->tm_hour
* MINS_PER_HOUR
+ tm
->tm_min
) * SECS_PER_MINUTE
) + tm
->tm_sec
+ fsec
;
1796 timetz_in(PG_FUNCTION_ARGS
)
1798 char *str
= PG_GETARG_CSTRING(0);
1801 Oid typelem
= PG_GETARG_OID(1);
1803 int32 typmod
= PG_GETARG_INT32(2);
1811 char workbuf
[MAXDATELEN
+ 1];
1812 char *field
[MAXDATEFIELDS
];
1814 int ftype
[MAXDATEFIELDS
];
1816 dterr
= ParseDateTime(str
, workbuf
, sizeof(workbuf
),
1817 field
, ftype
, MAXDATEFIELDS
, &nf
);
1819 dterr
= DecodeTimeOnly(field
, ftype
, nf
, &dtype
, tm
, &fsec
, &tz
);
1821 DateTimeParseError(dterr
, str
, "time with time zone");
1823 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
1824 tm2timetz(tm
, fsec
, tz
, result
);
1825 AdjustTimeForTypmod(&(result
->time
), typmod
);
1827 PG_RETURN_TIMETZADT_P(result
);
1831 timetz_out(PG_FUNCTION_ARGS
)
1833 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(0);
1839 char buf
[MAXDATELEN
+ 1];
1841 timetz2tm(time
, tm
, &fsec
, &tz
);
1842 EncodeTimeOnly(tm
, fsec
, &tz
, DateStyle
, buf
);
1844 result
= pstrdup(buf
);
1845 PG_RETURN_CSTRING(result
);
1849 * timetz_recv - converts external binary format to timetz
1852 timetz_recv(PG_FUNCTION_ARGS
)
1854 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
1857 Oid typelem
= PG_GETARG_OID(1);
1859 int32 typmod
= PG_GETARG_INT32(2);
1862 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
1864 #ifdef HAVE_INT64_TIMESTAMP
1865 result
->time
= pq_getmsgint64(buf
);
1867 if (result
->time
< INT64CONST(0) || result
->time
> USECS_PER_DAY
)
1869 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1870 errmsg("time out of range")));
1872 result
->time
= pq_getmsgfloat8(buf
);
1874 if (result
->time
< 0 || result
->time
> (double) SECS_PER_DAY
)
1876 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
1877 errmsg("time out of range")));
1880 result
->zone
= pq_getmsgint(buf
, sizeof(result
->zone
));
1882 /* we allow GMT displacements up to 14:59:59, cf DecodeTimezone() */
1883 if (result
->zone
<= -15 * SECS_PER_HOUR
||
1884 result
->zone
>= 15 * SECS_PER_HOUR
)
1886 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE
),
1887 errmsg("time zone displacement out of range")));
1889 AdjustTimeForTypmod(&(result
->time
), typmod
);
1891 PG_RETURN_TIMETZADT_P(result
);
1895 * timetz_send - converts timetz to binary format
1898 timetz_send(PG_FUNCTION_ARGS
)
1900 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(0);
1903 pq_begintypsend(&buf
);
1904 #ifdef HAVE_INT64_TIMESTAMP
1905 pq_sendint64(&buf
, time
->time
);
1907 pq_sendfloat8(&buf
, time
->time
);
1909 pq_sendint(&buf
, time
->zone
, sizeof(time
->zone
));
1910 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
1914 timetztypmodin(PG_FUNCTION_ARGS
)
1916 ArrayType
*ta
= PG_GETARG_ARRAYTYPE_P(0);
1918 PG_RETURN_INT32(anytime_typmodin(true, ta
));
1922 timetztypmodout(PG_FUNCTION_ARGS
)
1924 int32 typmod
= PG_GETARG_INT32(0);
1926 PG_RETURN_CSTRING(anytime_typmodout(true, typmod
));
1931 * Convert TIME WITH TIME ZONE data type to POSIX time structure.
1934 timetz2tm(TimeTzADT
*time
, struct pg_tm
* tm
, fsec_t
*fsec
, int *tzp
)
1936 TimeOffset trem
= time
->time
;
1938 #ifdef HAVE_INT64_TIMESTAMP
1939 tm
->tm_hour
= trem
/ USECS_PER_HOUR
;
1940 trem
-= tm
->tm_hour
* USECS_PER_HOUR
;
1941 tm
->tm_min
= trem
/ USECS_PER_MINUTE
;
1942 trem
-= tm
->tm_min
* USECS_PER_MINUTE
;
1943 tm
->tm_sec
= trem
/ USECS_PER_SEC
;
1944 *fsec
= trem
- tm
->tm_sec
* USECS_PER_SEC
;
1947 TMODULO(trem
, tm
->tm_hour
, (double) SECS_PER_HOUR
);
1948 TMODULO(trem
, tm
->tm_min
, (double) SECS_PER_MINUTE
);
1949 TMODULO(trem
, tm
->tm_sec
, 1.0);
1950 trem
= TIMEROUND(trem
);
1951 /* roundoff may need to propagate to higher-order fields */
1954 trem
= ceil(time
->time
);
1967 * Adjust time type for specified scale factor.
1968 * Used by PostgreSQL type system to stuff columns.
1971 timetz_scale(PG_FUNCTION_ARGS
)
1973 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(0);
1974 int32 typmod
= PG_GETARG_INT32(1);
1977 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
1979 result
->time
= time
->time
;
1980 result
->zone
= time
->zone
;
1982 AdjustTimeForTypmod(&(result
->time
), typmod
);
1984 PG_RETURN_TIMETZADT_P(result
);
1989 timetz_cmp_internal(TimeTzADT
*time1
, TimeTzADT
*time2
)
1994 /* Primary sort is by true (GMT-equivalent) time */
1995 #ifdef HAVE_INT64_TIMESTAMP
1996 t1
= time1
->time
+ (time1
->zone
* USECS_PER_SEC
);
1997 t2
= time2
->time
+ (time2
->zone
* USECS_PER_SEC
);
1999 t1
= time1
->time
+ time1
->zone
;
2000 t2
= time2
->time
+ time2
->zone
;
2009 * If same GMT time, sort by timezone; we only want to say that two
2010 * timetz's are equal if both the time and zone parts are equal.
2012 if (time1
->zone
> time2
->zone
)
2014 if (time1
->zone
< time2
->zone
)
2021 timetz_eq(PG_FUNCTION_ARGS
)
2023 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2024 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2026 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) == 0);
2030 timetz_ne(PG_FUNCTION_ARGS
)
2032 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2033 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2035 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) != 0);
2039 timetz_lt(PG_FUNCTION_ARGS
)
2041 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2042 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2044 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) < 0);
2048 timetz_le(PG_FUNCTION_ARGS
)
2050 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2051 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2053 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) <= 0);
2057 timetz_gt(PG_FUNCTION_ARGS
)
2059 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2060 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2062 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) > 0);
2066 timetz_ge(PG_FUNCTION_ARGS
)
2068 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2069 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2071 PG_RETURN_BOOL(timetz_cmp_internal(time1
, time2
) >= 0);
2075 timetz_cmp(PG_FUNCTION_ARGS
)
2077 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2078 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2080 PG_RETURN_INT32(timetz_cmp_internal(time1
, time2
));
2084 timetz_hash(PG_FUNCTION_ARGS
)
2086 TimeTzADT
*key
= PG_GETARG_TIMETZADT_P(0);
2090 * To avoid any problems with padding bytes in the struct, we figure the
2091 * field hashes separately and XOR them. This also provides a convenient
2092 * framework for dealing with the fact that the time field might be either
2095 #ifdef HAVE_INT64_TIMESTAMP
2096 thash
= DatumGetUInt32(DirectFunctionCall1(hashint8
,
2097 Int64GetDatumFast(key
->time
)));
2099 thash
= DatumGetUInt32(DirectFunctionCall1(hashfloat8
,
2100 Float8GetDatumFast(key
->time
)));
2102 thash
^= DatumGetUInt32(hash_uint32(key
->zone
));
2103 PG_RETURN_UINT32(thash
);
2107 timetz_larger(PG_FUNCTION_ARGS
)
2109 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2110 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2113 if (timetz_cmp_internal(time1
, time2
) > 0)
2117 PG_RETURN_TIMETZADT_P(result
);
2121 timetz_smaller(PG_FUNCTION_ARGS
)
2123 TimeTzADT
*time1
= PG_GETARG_TIMETZADT_P(0);
2124 TimeTzADT
*time2
= PG_GETARG_TIMETZADT_P(1);
2127 if (timetz_cmp_internal(time1
, time2
) < 0)
2131 PG_RETURN_TIMETZADT_P(result
);
2134 /* timetz_pl_interval()
2135 * Add interval to timetz.
2138 timetz_pl_interval(PG_FUNCTION_ARGS
)
2140 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(0);
2141 Interval
*span
= PG_GETARG_INTERVAL_P(1);
2144 #ifndef HAVE_INT64_TIMESTAMP
2148 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2150 #ifdef HAVE_INT64_TIMESTAMP
2151 result
->time
= time
->time
+ span
->time
;
2152 result
->time
-= result
->time
/ USECS_PER_DAY
* USECS_PER_DAY
;
2153 if (result
->time
< INT64CONST(0))
2154 result
->time
+= USECS_PER_DAY
;
2156 result
->time
= time
->time
+ span
->time
;
2157 TMODULO(result
->time
, time1
.time
, (double) SECS_PER_DAY
);
2158 if (result
->time
< 0)
2159 result
->time
+= SECS_PER_DAY
;
2162 result
->zone
= time
->zone
;
2164 PG_RETURN_TIMETZADT_P(result
);
2167 /* timetz_mi_interval()
2168 * Subtract interval from timetz.
2171 timetz_mi_interval(PG_FUNCTION_ARGS
)
2173 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(0);
2174 Interval
*span
= PG_GETARG_INTERVAL_P(1);
2177 #ifndef HAVE_INT64_TIMESTAMP
2181 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2183 #ifdef HAVE_INT64_TIMESTAMP
2184 result
->time
= time
->time
- span
->time
;
2185 result
->time
-= result
->time
/ USECS_PER_DAY
* USECS_PER_DAY
;
2186 if (result
->time
< INT64CONST(0))
2187 result
->time
+= USECS_PER_DAY
;
2189 result
->time
= time
->time
- span
->time
;
2190 TMODULO(result
->time
, time1
.time
, (double) SECS_PER_DAY
);
2191 if (result
->time
< 0)
2192 result
->time
+= SECS_PER_DAY
;
2195 result
->zone
= time
->zone
;
2197 PG_RETURN_TIMETZADT_P(result
);
2200 /* overlaps_timetz() --- implements the SQL92 OVERLAPS operator.
2202 * Algorithm is per SQL92 spec. This is much harder than you'd think
2203 * because the spec requires us to deliver a non-null answer in some cases
2204 * where some of the inputs are null.
2207 overlaps_timetz(PG_FUNCTION_ARGS
)
2210 * The arguments are TimeTzADT *, but we leave them as generic Datums for
2211 * convenience of notation --- and to avoid dereferencing nulls.
2213 Datum ts1
= PG_GETARG_DATUM(0);
2214 Datum te1
= PG_GETARG_DATUM(1);
2215 Datum ts2
= PG_GETARG_DATUM(2);
2216 Datum te2
= PG_GETARG_DATUM(3);
2217 bool ts1IsNull
= PG_ARGISNULL(0);
2218 bool te1IsNull
= PG_ARGISNULL(1);
2219 bool ts2IsNull
= PG_ARGISNULL(2);
2220 bool te2IsNull
= PG_ARGISNULL(3);
2222 #define TIMETZ_GT(t1,t2) \
2223 DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2224 #define TIMETZ_LT(t1,t2) \
2225 DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2228 * If both endpoints of interval 1 are null, the result is null (unknown).
2229 * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2230 * take ts1 as the lesser endpoint.
2236 /* swap null for non-null */
2240 else if (!te1IsNull
)
2242 if (TIMETZ_GT(ts1
, te1
))
2251 /* Likewise for interval 2. */
2256 /* swap null for non-null */
2260 else if (!te2IsNull
)
2262 if (TIMETZ_GT(ts2
, te2
))
2272 * At this point neither ts1 nor ts2 is null, so we can consider three
2273 * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2275 if (TIMETZ_GT(ts1
, ts2
))
2278 * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2279 * in the presence of nulls it's not quite completely so.
2283 if (TIMETZ_LT(ts1
, te2
))
2284 PG_RETURN_BOOL(true);
2289 * If te1 is not null then we had ts1 <= te1 above, and we just found
2290 * ts1 >= te2, hence te1 >= te2.
2292 PG_RETURN_BOOL(false);
2294 else if (TIMETZ_LT(ts1
, ts2
))
2296 /* This case is ts2 < te1 OR te2 < te1 */
2299 if (TIMETZ_LT(ts2
, te1
))
2300 PG_RETURN_BOOL(true);
2305 * If te2 is not null then we had ts2 <= te2 above, and we just found
2306 * ts2 >= te1, hence te2 >= te1.
2308 PG_RETURN_BOOL(false);
2313 * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2314 * rather silly way of saying "true if both are nonnull, else null".
2316 if (te1IsNull
|| te2IsNull
)
2318 PG_RETURN_BOOL(true);
2327 timetz_time(PG_FUNCTION_ARGS
)
2329 TimeTzADT
*timetz
= PG_GETARG_TIMETZADT_P(0);
2332 /* swallow the time zone and just return the time */
2333 result
= timetz
->time
;
2335 PG_RETURN_TIMEADT(result
);
2340 time_timetz(PG_FUNCTION_ARGS
)
2342 TimeADT time
= PG_GETARG_TIMEADT(0);
2349 GetCurrentDateTime(tm
);
2350 time2tm(time
, tm
, &fsec
);
2351 tz
= DetermineTimeZoneOffset(tm
, session_timezone
);
2353 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2355 result
->time
= time
;
2358 PG_RETURN_TIMETZADT_P(result
);
2362 /* timestamptz_timetz()
2363 * Convert timestamp to timetz data type.
2366 timestamptz_timetz(PG_FUNCTION_ARGS
)
2368 TimestampTz timestamp
= PG_GETARG_TIMESTAMP(0);
2376 if (TIMESTAMP_NOT_FINITE(timestamp
))
2379 if (timestamp2tm(timestamp
, &tz
, tm
, &fsec
, &tzn
, NULL
) != 0)
2381 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE
),
2382 errmsg("timestamp out of range")));
2384 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2386 tm2timetz(tm
, fsec
, tz
, result
);
2388 PG_RETURN_TIMETZADT_P(result
);
2392 /* datetimetz_timestamptz()
2393 * Convert date and timetz to timestamp with time zone data type.
2394 * Timestamp is stored in GMT, so add the time zone
2395 * stored with the timetz to the result.
2396 * - thomas 2000-03-10
2399 datetimetz_timestamptz(PG_FUNCTION_ARGS
)
2401 DateADT date
= PG_GETARG_DATEADT(0);
2402 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(1);
2405 if (DATE_IS_NOBEGIN(date
))
2406 TIMESTAMP_NOBEGIN(result
);
2407 else if (DATE_IS_NOEND(date
))
2408 TIMESTAMP_NOEND(result
);
2411 #ifdef HAVE_INT64_TIMESTAMP
2412 result
= date
* USECS_PER_DAY
+ time
->time
+ time
->zone
* USECS_PER_SEC
;
2414 result
= date
* (double) SECS_PER_DAY
+ time
->time
+ time
->zone
;
2418 PG_RETURN_TIMESTAMP(result
);
2423 * Extract specified field from time type.
2426 timetz_part(PG_FUNCTION_ARGS
)
2428 text
*units
= PG_GETARG_TEXT_PP(0);
2429 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(1);
2435 lowunits
= downcase_truncate_identifier(VARDATA_ANY(units
),
2436 VARSIZE_ANY_EXHDR(units
),
2439 type
= DecodeUnits(0, lowunits
, &val
);
2440 if (type
== UNKNOWN_FIELD
)
2441 type
= DecodeSpecial(0, lowunits
, &val
);
2451 timetz2tm(time
, tm
, &fsec
, &tz
);
2461 result
/= SECS_PER_MINUTE
;
2462 FMODULO(result
, dummy
, (double) SECS_PER_MINUTE
);
2467 FMODULO(dummy
, result
, (double) SECS_PER_HOUR
);
2471 #ifdef HAVE_INT64_TIMESTAMP
2472 result
= tm
->tm_sec
* USECS_PER_SEC
+ fsec
;
2474 result
= (tm
->tm_sec
+ fsec
) * 1000000;
2479 #ifdef HAVE_INT64_TIMESTAMP
2480 result
= tm
->tm_sec
* INT64CONST(1000) + fsec
/ INT64CONST(1000);
2482 result
= (tm
->tm_sec
+ fsec
) * 1000;
2487 #ifdef HAVE_INT64_TIMESTAMP
2488 result
= tm
->tm_sec
+ fsec
/ USECS_PER_SEC
;
2490 result
= tm
->tm_sec
+ fsec
;
2495 result
= tm
->tm_min
;
2499 result
= tm
->tm_hour
;
2508 case DTK_MILLENNIUM
:
2511 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2512 errmsg("\"time with time zone\" units \"%s\" not recognized",
2517 else if (type
== RESERV
&& val
== DTK_EPOCH
)
2519 #ifdef HAVE_INT64_TIMESTAMP
2520 result
= time
->time
/ 1000000.0 + time
->zone
;
2522 result
= time
->time
+ time
->zone
;
2528 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2529 errmsg("\"time with time zone\" units \"%s\" not recognized",
2534 PG_RETURN_FLOAT8(result
);
2538 * Encode time with time zone type with specified time zone.
2539 * Applies DST rules as of the current date.
2542 timetz_zone(PG_FUNCTION_ARGS
)
2544 text
*zone
= PG_GETARG_TEXT_PP(0);
2545 TimeTzADT
*t
= PG_GETARG_TIMETZADT_P(1);
2548 char tzname
[TZ_STRLEN_MAX
+ 1];
2555 * Look up the requested timezone. First we look in the date token table
2556 * (to handle cases like "EST"), and if that fails, we look in the
2557 * timezone database (to handle cases like "America/New_York"). (This
2558 * matches the order in which timestamp input checks the cases; it's
2559 * important because the timezone database unwisely uses a few zone names
2560 * that are identical to offset abbreviations.)
2562 text_to_cstring_buffer(zone
, tzname
, sizeof(tzname
));
2563 lowzone
= downcase_truncate_identifier(tzname
,
2567 type
= DecodeSpecial(0, lowzone
, &val
);
2569 if (type
== TZ
|| type
== DTZ
)
2573 tzp
= pg_tzset(tzname
);
2576 /* Get the offset-from-GMT that is valid today for the zone */
2577 pg_time_t now
= (pg_time_t
) time(NULL
);
2580 tm
= pg_localtime(&now
, tzp
);
2581 tz
= -tm
->tm_gmtoff
;
2586 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2587 errmsg("time zone \"%s\" not recognized", tzname
)));
2588 tz
= 0; /* keep compiler quiet */
2592 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2594 #ifdef HAVE_INT64_TIMESTAMP
2595 result
->time
= t
->time
+ (t
->zone
- tz
) * USECS_PER_SEC
;
2596 while (result
->time
< INT64CONST(0))
2597 result
->time
+= USECS_PER_DAY
;
2598 while (result
->time
>= USECS_PER_DAY
)
2599 result
->time
-= USECS_PER_DAY
;
2601 result
->time
= t
->time
+ (t
->zone
- tz
);
2602 while (result
->time
< 0)
2603 result
->time
+= SECS_PER_DAY
;
2604 while (result
->time
>= SECS_PER_DAY
)
2605 result
->time
-= SECS_PER_DAY
;
2610 PG_RETURN_TIMETZADT_P(result
);
2614 * Encode time with time zone type with specified time interval as time zone.
2617 timetz_izone(PG_FUNCTION_ARGS
)
2619 Interval
*zone
= PG_GETARG_INTERVAL_P(0);
2620 TimeTzADT
*time
= PG_GETARG_TIMETZADT_P(1);
2624 if (zone
->month
!= 0)
2626 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2627 errmsg("\"interval\" time zone \"%s\" not valid",
2628 DatumGetCString(DirectFunctionCall1(interval_out
,
2629 PointerGetDatum(zone
))))));
2631 #ifdef HAVE_INT64_TIMESTAMP
2632 tz
= -(zone
->time
/ USECS_PER_SEC
);
2637 result
= (TimeTzADT
*) palloc(sizeof(TimeTzADT
));
2639 #ifdef HAVE_INT64_TIMESTAMP
2640 result
->time
= time
->time
+ (time
->zone
- tz
) * USECS_PER_SEC
;
2641 while (result
->time
< INT64CONST(0))
2642 result
->time
+= USECS_PER_DAY
;
2643 while (result
->time
>= USECS_PER_DAY
)
2644 result
->time
-= USECS_PER_DAY
;
2646 result
->time
= time
->time
+ (time
->zone
- tz
);
2647 while (result
->time
< 0)
2648 result
->time
+= SECS_PER_DAY
;
2649 while (result
->time
>= SECS_PER_DAY
)
2650 result
->time
-= SECS_PER_DAY
;
2655 PG_RETURN_TIMETZADT_P(result
);