1 /*-------------------------------------------------------------------------
4 * Utilities for the built-in type "AbsoluteTime".
5 * Functions for the built-in type "RelativeTime".
6 * Functions for the built-in type "TimeInterval".
8 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/backend/utils/adt/nabstime.c
15 *-------------------------------------------------------------------------
25 #include "libpq/pqformat.h"
26 #include "miscadmin.h"
27 #include "utils/builtins.h"
28 #include "utils/datetime.h"
29 #include "utils/nabstime.h"
31 #define MIN_DAYNUM (-24856) /* December 13, 1901 */
32 #define MAX_DAYNUM 24854 /* January 18, 2038 */
35 * Unix epoch is Jan 1 00:00:00 1970.
36 * Postgres knows about times sixty-eight years on either side of that
37 * for these 4-byte types.
39 * "tinterval" is two 4-byte fields.
40 * Definitions for parsing tinterval.
43 #define IsSpace(C) ((C) == ' ')
45 #define T_INTERVAL_INVAL 0 /* data represents no valid tinterval */
46 #define T_INTERVAL_VALID 1 /* data represents a valid tinterval */
48 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
50 * 1234567890123456789012345678901234567890123456789012345678901234
52 * we allocate some extra -- timezones are usually 3 characters but
53 * this is not in the POSIX standard...
55 #define T_INTERVAL_LEN 80
56 #define INVALID_INTERVAL_STR "Undefined Range"
57 #define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
59 #define ABSTIMEMIN(t1, t2) \
60 (DatumGetBool(DirectFunctionCall2(abstimele, \
61 AbsoluteTimeGetDatum(t1), \
62 AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
63 #define ABSTIMEMAX(t1, t2) \
64 (DatumGetBool(DirectFunctionCall2(abstimelt, \
65 AbsoluteTimeGetDatum(t1), \
66 AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
70 * Function prototypes -- internal to this file only
73 static AbsoluteTime tm2abstime(struct pg_tm * tm, int tz);
74 static void reltime2tm(RelativeTime time, struct pg_tm * tm);
75 static void parsetinterval(char *i_string,
76 AbsoluteTime *i_start,
81 * GetCurrentAbsoluteTime()
83 * Get the current system time (relative to Unix epoch).
85 * NB: this will overflow in 2038; it should be gone long before that.
88 GetCurrentAbsoluteTime(void)
93 return (AbsoluteTime) now;
98 abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
100 pg_time_t time = (pg_time_t) _time;
104 tx = pg_localtime(&time, session_timezone);
106 tx = pg_gmtime(&time);
108 tm->tm_year = tx->tm_year + 1900;
109 tm->tm_mon = tx->tm_mon + 1;
110 tm->tm_mday = tx->tm_mday;
111 tm->tm_hour = tx->tm_hour;
112 tm->tm_min = tx->tm_min;
113 tm->tm_sec = tx->tm_sec;
114 tm->tm_isdst = tx->tm_isdst;
116 tm->tm_gmtoff = tx->tm_gmtoff;
117 tm->tm_zone = tx->tm_zone;
121 *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
124 * XXX FreeBSD man pages indicate that this should work - tgl
130 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
131 * case it contains an error message, which doesn't fit in the
134 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
135 if (strlen(tm->tm_zone) > MAXTZLEN)
137 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
138 errmsg("invalid time zone name: \"%s\"",
148 * Convert a tm structure to abstime.
149 * Note that tm has full year (not 1900-based) and 1-based month.
152 tm2abstime(struct pg_tm * tm, int tz)
157 /* validate, before going out of range on some members */
158 if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
159 tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
160 tm->tm_mday < 1 || tm->tm_mday > 31 ||
162 tm->tm_hour > HOURS_PER_DAY || /* test for > 24:00:00 */
163 (tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
164 tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
165 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
166 return INVALID_ABSTIME;
168 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
170 /* check for time out of range */
171 if (day < MIN_DAYNUM || day > MAX_DAYNUM)
172 return INVALID_ABSTIME;
174 /* convert to seconds */
175 sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE;
178 * check for overflow. We need a little slop here because the H/M/S plus
179 * TZ offset could add up to more than 1 day.
181 if ((day >= MAX_DAYNUM - 10 && sec < 0) ||
182 (day <= MIN_DAYNUM + 10 && sec > 0))
183 return INVALID_ABSTIME;
185 /* check for reserved values (e.g. "current" on edge of usual range */
186 if (!AbsoluteTimeIsReal(sec))
187 return INVALID_ABSTIME;
194 * Decode date/time string and return abstime.
197 abstimein(PG_FUNCTION_ARGS)
199 char *str = PG_GETARG_CSTRING(0);
206 char *field[MAXDATEFIELDS];
207 char workbuf[MAXDATELEN + 1];
210 ftype[MAXDATEFIELDS];
212 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
213 field, ftype, MAXDATEFIELDS, &nf);
215 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
217 DateTimeParseError(dterr, str, "abstime");
222 result = tm2abstime(tm, tz);
228 * Don't bother retaining this as a reserved value, but instead
229 * just set to the actual epoch time (1970-01-01)
235 result = NOEND_ABSTIME;
239 result = NOSTART_ABSTIME;
243 result = INVALID_ABSTIME;
247 elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
249 result = INVALID_ABSTIME;
253 PG_RETURN_ABSOLUTETIME(result);
258 * Given an AbsoluteTime return the English text version of the date
261 abstimeout(PG_FUNCTION_ARGS)
263 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
269 char buf[MAXDATELEN + 1];
270 char zone[MAXDATELEN + 1],
276 * Note that timestamp no longer supports 'invalid'. Retain
277 * 'invalid' for abstime for now, but dump it someday.
279 case INVALID_ABSTIME:
280 strcpy(buf, INVALID);
285 case NOSTART_ABSTIME:
289 abstime2tm(time, &tz, tm, &tzn);
290 EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
294 result = pstrdup(buf);
295 PG_RETURN_CSTRING(result);
299 * abstimerecv - converts external binary format to abstime
302 abstimerecv(PG_FUNCTION_ARGS)
304 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
306 PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
310 * abstimesend - converts abstime to binary format
313 abstimesend(PG_FUNCTION_ARGS)
315 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
318 pq_begintypsend(&buf);
319 pq_sendint(&buf, time, sizeof(time));
320 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
327 abstime_finite(PG_FUNCTION_ARGS)
329 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
331 PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
332 abstime != NOSTART_ABSTIME &&
333 abstime != NOEND_ABSTIME);
338 * abstime comparison routines
341 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
344 * We consider all INVALIDs to be equal and larger than any non-INVALID.
345 * This is somewhat arbitrary; the important thing is to have a consistent
348 if (a == INVALID_ABSTIME)
350 if (b == INVALID_ABSTIME)
351 return 0; /* INVALID = INVALID */
353 return 1; /* INVALID > non-INVALID */
356 if (b == INVALID_ABSTIME)
357 return -1; /* non-INVALID < INVALID */
368 abstimeeq(PG_FUNCTION_ARGS)
370 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
371 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
373 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
377 abstimene(PG_FUNCTION_ARGS)
379 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
380 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
382 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
386 abstimelt(PG_FUNCTION_ARGS)
388 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
389 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
391 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
395 abstimegt(PG_FUNCTION_ARGS)
397 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
398 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
400 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
404 abstimele(PG_FUNCTION_ARGS)
406 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
407 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
409 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
413 abstimege(PG_FUNCTION_ARGS)
415 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
416 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
418 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
422 btabstimecmp(PG_FUNCTION_ARGS)
424 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
425 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
427 PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
431 /* timestamp_abstime()
432 * Convert timestamp to abstime.
435 timestamp_abstime(PG_FUNCTION_ARGS)
437 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
444 if (TIMESTAMP_IS_NOBEGIN(timestamp))
445 result = NOSTART_ABSTIME;
446 else if (TIMESTAMP_IS_NOEND(timestamp))
447 result = NOEND_ABSTIME;
448 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
450 tz = DetermineTimeZoneOffset(tm, session_timezone);
451 result = tm2abstime(tm, tz);
456 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
457 errmsg("timestamp out of range")));
458 result = INVALID_ABSTIME;
461 PG_RETURN_ABSOLUTETIME(result);
464 /* abstime_timestamp()
465 * Convert abstime to timestamp.
468 abstime_timestamp(PG_FUNCTION_ARGS)
470 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
475 char zone[MAXDATELEN + 1],
480 case INVALID_ABSTIME:
482 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
483 errmsg("cannot convert abstime \"invalid\" to timestamp")));
484 TIMESTAMP_NOBEGIN(result);
487 case NOSTART_ABSTIME:
488 TIMESTAMP_NOBEGIN(result);
492 TIMESTAMP_NOEND(result);
496 abstime2tm(abstime, &tz, tm, &tzn);
497 if (tm2timestamp(tm, 0, NULL, &result) != 0)
499 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
500 errmsg("timestamp out of range")));
504 PG_RETURN_TIMESTAMP(result);
508 /* timestamptz_abstime()
509 * Convert timestamp with time zone to abstime.
512 timestamptz_abstime(PG_FUNCTION_ARGS)
514 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
520 if (TIMESTAMP_IS_NOBEGIN(timestamp))
521 result = NOSTART_ABSTIME;
522 else if (TIMESTAMP_IS_NOEND(timestamp))
523 result = NOEND_ABSTIME;
524 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
525 result = tm2abstime(tm, 0);
529 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
530 errmsg("timestamp out of range")));
531 result = INVALID_ABSTIME;
534 PG_RETURN_ABSOLUTETIME(result);
537 /* abstime_timestamptz()
538 * Convert abstime to timestamp with time zone.
541 abstime_timestamptz(PG_FUNCTION_ARGS)
543 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
548 char zone[MAXDATELEN + 1],
553 case INVALID_ABSTIME:
555 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
556 errmsg("cannot convert abstime \"invalid\" to timestamp")));
557 TIMESTAMP_NOBEGIN(result);
560 case NOSTART_ABSTIME:
561 TIMESTAMP_NOBEGIN(result);
565 TIMESTAMP_NOEND(result);
569 abstime2tm(abstime, &tz, tm, &tzn);
570 if (tm2timestamp(tm, 0, &tz, &result) != 0)
572 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
573 errmsg("timestamp out of range")));
577 PG_RETURN_TIMESTAMP(result);
581 /*****************************************************************************
582 * USER I/O ROUTINES *
583 *****************************************************************************/
586 * reltimein - converts a reltime string in an internal format
589 reltimein(PG_FUNCTION_ARGS)
591 char *str = PG_GETARG_CSTRING(0);
598 char *field[MAXDATEFIELDS];
600 ftype[MAXDATEFIELDS];
601 char workbuf[MAXDATELEN + 1];
603 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
604 field, ftype, MAXDATEFIELDS, &nf);
606 dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
609 /* if those functions think it's a bad format, try ISO8601 style */
610 if (dterr == DTERR_BAD_FORMAT)
611 dterr = DecodeISO8601Interval(str,
616 if (dterr == DTERR_FIELD_OVERFLOW)
617 dterr = DTERR_INTERVAL_OVERFLOW;
618 DateTimeParseError(dterr, str, "reltime");
624 result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec;
625 result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY;
629 elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
631 result = INVALID_RELTIME;
635 PG_RETURN_RELATIVETIME(result);
639 * reltimeout - converts the internal format to a reltime string
642 reltimeout(PG_FUNCTION_ARGS)
644 RelativeTime time = PG_GETARG_RELATIVETIME(0);
648 char buf[MAXDATELEN + 1];
650 reltime2tm(time, tm);
651 EncodeInterval(tm, 0, IntervalStyle, buf);
653 result = pstrdup(buf);
654 PG_RETURN_CSTRING(result);
658 * reltimerecv - converts external binary format to reltime
661 reltimerecv(PG_FUNCTION_ARGS)
663 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
665 PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
669 * reltimesend - converts reltime to binary format
672 reltimesend(PG_FUNCTION_ARGS)
674 RelativeTime time = PG_GETARG_RELATIVETIME(0);
677 pq_begintypsend(&buf);
678 pq_sendint(&buf, time, sizeof(time));
679 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
684 reltime2tm(RelativeTime time, struct pg_tm * tm)
688 FMODULO(dtime, tm->tm_year, 31557600);
689 FMODULO(dtime, tm->tm_mon, 2592000);
690 FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
691 FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR);
692 FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE);
693 FMODULO(dtime, tm->tm_sec, 1);
698 * tintervalin - converts an tinterval string to internal format
701 tintervalin(PG_FUNCTION_ARGS)
703 char *tintervalstr = PG_GETARG_CSTRING(0);
704 TimeInterval tinterval;
705 AbsoluteTime i_start,
710 parsetinterval(tintervalstr, &t1, &t2);
712 tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
714 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
715 tinterval->status = T_INTERVAL_INVAL; /* undefined */
717 tinterval->status = T_INTERVAL_VALID;
719 i_start = ABSTIMEMIN(t1, t2);
720 i_end = ABSTIMEMAX(t1, t2);
721 tinterval->data[0] = i_start;
722 tinterval->data[1] = i_end;
724 PG_RETURN_TIMEINTERVAL(tinterval);
729 * tintervalout - converts an internal tinterval format to a string
732 tintervalout(PG_FUNCTION_ARGS)
734 TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
738 i_str = (char *) palloc(T_INTERVAL_LEN); /* ["..." "..."] */
739 strcpy(i_str, "[\"");
740 if (tinterval->status == T_INTERVAL_INVAL)
741 strcat(i_str, INVALID_INTERVAL_STR);
744 p = DatumGetCString(DirectFunctionCall1(abstimeout,
745 AbsoluteTimeGetDatum(tinterval->data[0])));
748 strcat(i_str, "\" \"");
749 p = DatumGetCString(DirectFunctionCall1(abstimeout,
750 AbsoluteTimeGetDatum(tinterval->data[1])));
754 strcat(i_str, "\"]");
755 PG_RETURN_CSTRING(i_str);
759 * tintervalrecv - converts external binary format to tinterval
762 tintervalrecv(PG_FUNCTION_ARGS)
764 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
765 TimeInterval tinterval;
768 tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
770 tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
771 tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
772 tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
774 if (tinterval->data[0] == INVALID_ABSTIME ||
775 tinterval->data[1] == INVALID_ABSTIME)
776 status = T_INTERVAL_INVAL; /* undefined */
778 status = T_INTERVAL_VALID;
780 if (status != tinterval->status)
782 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
783 errmsg("invalid status in external \"tinterval\" value")));
785 PG_RETURN_TIMEINTERVAL(tinterval);
789 * tintervalsend - converts tinterval to binary format
792 tintervalsend(PG_FUNCTION_ARGS)
794 TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
797 pq_begintypsend(&buf);
798 pq_sendint(&buf, tinterval->status, sizeof(tinterval->status));
799 pq_sendint(&buf, tinterval->data[0], sizeof(tinterval->data[0]));
800 pq_sendint(&buf, tinterval->data[1], sizeof(tinterval->data[1]));
801 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
805 /*****************************************************************************
807 *****************************************************************************/
810 interval_reltime(PG_FUNCTION_ARGS)
812 Interval *interval = PG_GETARG_INTERVAL_P(0);
819 year = interval->month / MONTHS_PER_YEAR;
820 month = interval->month % MONTHS_PER_YEAR;
823 #ifdef HAVE_INT64_TIMESTAMP
824 span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
825 INT64CONST(1000000) * day) * INT64CONST(86400)) +
827 span /= USECS_PER_SEC;
829 span = (DAYS_PER_YEAR * year + (double) DAYS_PER_MONTH * month + day) * SECS_PER_DAY + interval->time;
832 if (span < INT_MIN || span > INT_MAX)
833 time = INVALID_RELTIME;
837 PG_RETURN_RELATIVETIME(time);
842 reltime_interval(PG_FUNCTION_ARGS)
844 RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
850 result = (Interval *) palloc(sizeof(Interval));
854 case INVALID_RELTIME:
856 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
857 errmsg("cannot convert reltime \"invalid\" to interval")));
864 #ifdef HAVE_INT64_TIMESTAMP
865 year = reltime / SECS_PER_YEAR;
866 reltime -= year * SECS_PER_YEAR;
867 month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY);
868 reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY);
869 day = reltime / SECS_PER_DAY;
870 reltime -= day * SECS_PER_DAY;
872 result->time = (reltime * USECS_PER_SEC);
874 TMODULO(reltime, year, SECS_PER_YEAR);
875 TMODULO(reltime, month, DAYS_PER_MONTH * SECS_PER_DAY);
876 TMODULO(reltime, day, SECS_PER_DAY);
878 result->time = reltime;
880 result->month = MONTHS_PER_YEAR * year + month;
885 PG_RETURN_INTERVAL_P(result);
890 * mktinterval - creates a time interval with endpoints t1 and t2
893 mktinterval(PG_FUNCTION_ARGS)
895 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
896 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
897 AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
898 AbsoluteTime tend = ABSTIMEMAX(t1, t2);
899 TimeInterval tinterval;
901 tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
903 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
904 tinterval->status = T_INTERVAL_INVAL;
908 tinterval->status = T_INTERVAL_VALID;
909 tinterval->data[0] = tstart;
910 tinterval->data[1] = tend;
913 PG_RETURN_TIMEINTERVAL(tinterval);
917 * timepl, timemi and abstimemi use the formula
918 * abstime + reltime = abstime
919 * so abstime - reltime = abstime
920 * and abstime - abstime = reltime
924 * timepl - returns the value of (abstime t1 + reltime t2)
927 timepl(PG_FUNCTION_ARGS)
929 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
930 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
932 if (AbsoluteTimeIsReal(t1) &&
933 RelativeTimeIsValid(t2) &&
934 ((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
935 (t2 <= 0 && t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
936 PG_RETURN_ABSOLUTETIME(t1 + t2);
938 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
943 * timemi - returns the value of (abstime t1 - reltime t2)
946 timemi(PG_FUNCTION_ARGS)
948 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
949 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
951 if (AbsoluteTimeIsReal(t1) &&
952 RelativeTimeIsValid(t2) &&
953 ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
954 (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
955 PG_RETURN_ABSOLUTETIME(t1 - t2);
957 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
962 * intinterval - returns true iff absolute date is in the tinterval
965 intinterval(PG_FUNCTION_ARGS)
967 AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
968 TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1);
970 if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
972 if (DatumGetBool(DirectFunctionCall2(abstimege,
973 AbsoluteTimeGetDatum(t),
974 AbsoluteTimeGetDatum(tinterval->data[0]))) &&
975 DatumGetBool(DirectFunctionCall2(abstimele,
976 AbsoluteTimeGetDatum(t),
977 AbsoluteTimeGetDatum(tinterval->data[1]))))
978 PG_RETURN_BOOL(true);
980 PG_RETURN_BOOL(false);
984 * tintervalrel - returns relative time corresponding to tinterval
987 tintervalrel(PG_FUNCTION_ARGS)
989 TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
990 AbsoluteTime t1 = tinterval->data[0];
991 AbsoluteTime t2 = tinterval->data[1];
993 if (tinterval->status != T_INTERVAL_VALID)
994 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
996 if (AbsoluteTimeIsReal(t1) &&
997 AbsoluteTimeIsReal(t2))
998 PG_RETURN_RELATIVETIME(t2 - t1);
1000 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1005 * timenow - returns time "now", internal format
1007 * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1010 timenow(PG_FUNCTION_ARGS)
1012 PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
1016 * reltime comparison routines
1019 reltime_cmp_internal(RelativeTime a, RelativeTime b)
1022 * We consider all INVALIDs to be equal and larger than any non-INVALID.
1023 * This is somewhat arbitrary; the important thing is to have a consistent
1026 if (a == INVALID_RELTIME)
1028 if (b == INVALID_RELTIME)
1029 return 0; /* INVALID = INVALID */
1031 return 1; /* INVALID > non-INVALID */
1034 if (b == INVALID_RELTIME)
1035 return -1; /* non-INVALID < INVALID */
1046 reltimeeq(PG_FUNCTION_ARGS)
1048 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1049 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1051 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1055 reltimene(PG_FUNCTION_ARGS)
1057 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1058 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1060 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1064 reltimelt(PG_FUNCTION_ARGS)
1066 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1067 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1069 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1073 reltimegt(PG_FUNCTION_ARGS)
1075 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1076 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1078 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1082 reltimele(PG_FUNCTION_ARGS)
1084 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1085 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1087 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1091 reltimege(PG_FUNCTION_ARGS)
1093 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1094 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1096 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
1100 btreltimecmp(PG_FUNCTION_ARGS)
1102 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1103 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1105 PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1110 * tintervalsame - returns true iff tinterval i1 is same as tinterval i2
1111 * Check begin and end time.
1114 tintervalsame(PG_FUNCTION_ARGS)
1116 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1117 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1119 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1120 PG_RETURN_BOOL(false);
1122 if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1123 AbsoluteTimeGetDatum(i1->data[0]),
1124 AbsoluteTimeGetDatum(i2->data[0]))) &&
1125 DatumGetBool(DirectFunctionCall2(abstimeeq,
1126 AbsoluteTimeGetDatum(i1->data[1]),
1127 AbsoluteTimeGetDatum(i2->data[1]))))
1128 PG_RETURN_BOOL(true);
1129 PG_RETURN_BOOL(false);
1133 * tinterval comparison routines
1135 * Note: comparison is based only on the lengths of the tintervals, not on
1136 * endpoint values (as long as they're not INVALID). This is pretty bogus,
1137 * but since it's only a legacy datatype, we're not going to change it.
1139 * Some other bogus things that won't be changed for compatibility reasons:
1140 * 1. The interval length computations overflow at 2^31 seconds, causing
1141 * intervals longer than that to sort oddly compared to those shorter.
1142 * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
1143 * just ordinary integers. Since this code doesn't handle them specially,
1144 * it's possible for [a b] to be considered longer than [c infinity] for
1145 * finite abstimes a, b, c. In combination with the previous point, the
1146 * interval [-infinity infinity] is treated as being shorter than many finite
1149 * If tinterval is ever reimplemented atop timestamp, it'd be good to give
1150 * some consideration to avoiding these problems.
1153 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1161 * We consider all INVALIDs to be equal and larger than any non-INVALID.
1162 * This is somewhat arbitrary; the important thing is to have a consistent
1165 a_invalid = a->status == T_INTERVAL_INVAL ||
1166 a->data[0] == INVALID_ABSTIME ||
1167 a->data[1] == INVALID_ABSTIME;
1168 b_invalid = b->status == T_INTERVAL_INVAL ||
1169 b->data[0] == INVALID_ABSTIME ||
1170 b->data[1] == INVALID_ABSTIME;
1175 return 0; /* INVALID = INVALID */
1177 return 1; /* INVALID > non-INVALID */
1181 return -1; /* non-INVALID < INVALID */
1183 a_len = a->data[1] - a->data[0];
1184 b_len = b->data[1] - b->data[0];
1188 else if (a_len == b_len)
1195 tintervaleq(PG_FUNCTION_ARGS)
1197 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1198 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1200 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
1204 tintervalne(PG_FUNCTION_ARGS)
1206 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1207 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1209 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1213 tintervallt(PG_FUNCTION_ARGS)
1215 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1216 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1218 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1222 tintervalle(PG_FUNCTION_ARGS)
1224 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1225 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1227 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1231 tintervalgt(PG_FUNCTION_ARGS)
1233 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1234 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1236 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1240 tintervalge(PG_FUNCTION_ARGS)
1242 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1243 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1245 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
1249 bttintervalcmp(PG_FUNCTION_ARGS)
1251 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1252 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1254 PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1259 * tintervalleneq - returns true iff length of tinterval i is equal to
1261 * tintervallenne - returns true iff length of tinterval i is not equal
1263 * tintervallenlt - returns true iff length of tinterval i is less than
1265 * tintervallengt - returns true iff length of tinterval i is greater
1267 * tintervallenle - returns true iff length of tinterval i is less or
1268 * equal than reltime t
1269 * tintervallenge - returns true iff length of tinterval i is greater or
1270 * equal than reltime t
1273 tintervalleneq(PG_FUNCTION_ARGS)
1275 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1276 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1279 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1280 PG_RETURN_BOOL(false);
1281 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1282 TimeIntervalGetDatum(i)));
1283 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1287 tintervallenne(PG_FUNCTION_ARGS)
1289 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1290 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1293 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1294 PG_RETURN_BOOL(false);
1295 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1296 TimeIntervalGetDatum(i)));
1297 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1301 tintervallenlt(PG_FUNCTION_ARGS)
1303 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1304 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1307 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1308 PG_RETURN_BOOL(false);
1309 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1310 TimeIntervalGetDatum(i)));
1311 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1315 tintervallengt(PG_FUNCTION_ARGS)
1317 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1318 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1321 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1322 PG_RETURN_BOOL(false);
1323 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1324 TimeIntervalGetDatum(i)));
1325 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1329 tintervallenle(PG_FUNCTION_ARGS)
1331 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1332 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1335 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1336 PG_RETURN_BOOL(false);
1337 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1338 TimeIntervalGetDatum(i)));
1339 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1343 tintervallenge(PG_FUNCTION_ARGS)
1345 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1346 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1349 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1350 PG_RETURN_BOOL(false);
1351 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1352 TimeIntervalGetDatum(i)));
1353 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1357 * tintervalct - returns true iff tinterval i1 contains tinterval i2
1360 tintervalct(PG_FUNCTION_ARGS)
1362 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1363 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1365 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1366 PG_RETURN_BOOL(false);
1367 if (DatumGetBool(DirectFunctionCall2(abstimele,
1368 AbsoluteTimeGetDatum(i1->data[0]),
1369 AbsoluteTimeGetDatum(i2->data[0]))) &&
1370 DatumGetBool(DirectFunctionCall2(abstimege,
1371 AbsoluteTimeGetDatum(i1->data[1]),
1372 AbsoluteTimeGetDatum(i2->data[1]))))
1373 PG_RETURN_BOOL(true);
1374 PG_RETURN_BOOL(false);
1378 * tintervalov - returns true iff tinterval i1 (partially) overlaps i2
1381 tintervalov(PG_FUNCTION_ARGS)
1383 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1384 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1386 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1387 PG_RETURN_BOOL(false);
1388 if (DatumGetBool(DirectFunctionCall2(abstimelt,
1389 AbsoluteTimeGetDatum(i1->data[1]),
1390 AbsoluteTimeGetDatum(i2->data[0]))) ||
1391 DatumGetBool(DirectFunctionCall2(abstimegt,
1392 AbsoluteTimeGetDatum(i1->data[0]),
1393 AbsoluteTimeGetDatum(i2->data[1]))))
1394 PG_RETURN_BOOL(false);
1395 PG_RETURN_BOOL(true);
1399 * tintervalstart - returns the start of tinterval i
1402 tintervalstart(PG_FUNCTION_ARGS)
1404 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1406 if (i->status == T_INTERVAL_INVAL)
1407 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1408 PG_RETURN_ABSOLUTETIME(i->data[0]);
1412 * tintervalend - returns the end of tinterval i
1415 tintervalend(PG_FUNCTION_ARGS)
1417 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1419 if (i->status == T_INTERVAL_INVAL)
1420 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1421 PG_RETURN_ABSOLUTETIME(i->data[1]);
1425 /*****************************************************************************
1426 * PRIVATE ROUTINES *
1427 *****************************************************************************/
1430 * parsetinterval -- parse a tinterval string
1432 * output parameters:
1433 * i_start, i_end: tinterval margins
1436 * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1438 * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
1440 * where <AbsTime> satisfies the syntax of absolute time.
1442 * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
1445 parsetinterval(char *i_string,
1446 AbsoluteTime *i_start,
1447 AbsoluteTime *i_end)
1454 /* skip leading blanks up to '[' */
1455 while ((c = *p) != '\0')
1460 goto bogus; /* syntax error */
1465 goto bogus; /* syntax error */
1467 /* skip leading blanks up to '"' */
1468 while ((c = *p) != '\0')
1473 goto bogus; /* syntax error */
1478 goto bogus; /* syntax error */
1480 if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1481 goto bogus; /* undefined range, handled like a syntax err. */
1482 /* search for the end of the first date and change it to a \0 */
1484 while ((c = *p1) != '\0')
1491 goto bogus; /* syntax error */
1493 /* get the first date */
1494 *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1495 CStringGetDatum(p)));
1496 /* undo change to \0 */
1499 /* skip blanks up to '"', beginning of second date */
1500 while ((c = *p) != '\0')
1505 goto bogus; /* syntax error */
1510 goto bogus; /* syntax error */
1512 /* search for the end of the second date and change it to a \0 */
1514 while ((c = *p1) != '\0')
1521 goto bogus; /* syntax error */
1523 /* get the second date */
1524 *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1525 CStringGetDatum(p)));
1526 /* undo change to \0 */
1529 /* skip blanks up to ']' */
1530 while ((c = *p) != '\0')
1535 goto bogus; /* syntax error */
1540 goto bogus; /* syntax error */
1544 goto bogus; /* syntax error */
1546 /* it seems to be a valid tinterval */
1551 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1552 errmsg("invalid input syntax for type tinterval: \"%s\"",
1554 *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */
1558 /*****************************************************************************
1560 *****************************************************************************/
1564 * returns the current time as a text. similar to timenow() but returns
1565 * seconds with more precision (up to microsecs). (I need this to compare
1566 * the Wisconsin benchmark with Illustra whose TimeNow() shows current
1567 * time with precision up to microsecs.) - ay 3/95
1570 timeofday(PG_FUNCTION_ARGS)
1577 gettimeofday(&tp, NULL);
1578 tt = (pg_time_t) tp.tv_sec;
1579 pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1580 pg_localtime(&tt, session_timezone));
1581 snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1583 PG_RETURN_TEXT_P(cstring_to_text(buf));