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-2005, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.134 2005/06/29 22:51:56 tgl Exp $
15 *-------------------------------------------------------------------------
25 #include "access/xact.h"
26 #include "libpq/pqformat.h"
27 #include "miscadmin.h"
29 #include "utils/builtins.h"
30 #include "utils/nabstime.h"
32 #define MIN_DAYNUM -24856 /* December 13, 1901 */
33 #define MAX_DAYNUM 24854 /* January 18, 2038 */
35 #define INVALID_RELTIME_STR "Undefined RelTime"
36 #define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
37 #define RELTIME_LABEL '@'
38 #define RELTIME_PAST "ago"
39 #define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
42 * Unix epoch is Jan 1 00:00:00 1970.
43 * Postgres knows about times sixty-eight years on either side of that
44 * for these 4-byte types.
46 * "tinterval" is two 4-byte fields.
47 * Definitions for parsing tinterval.
50 #define IsSpace(C) ((C) == ' ')
52 #define T_INTERVAL_INVAL 0 /* data represents no valid interval */
53 #define T_INTERVAL_VALID 1 /* data represents a valid interval */
55 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
57 * 1234567890123456789012345678901234567890123456789012345678901234
59 * we allocate some extra -- timezones are usually 3 characters but
60 * this is not in the POSIX standard...
62 #define T_INTERVAL_LEN 80
63 #define INVALID_INTERVAL_STR "Undefined Range"
64 #define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
66 #define ABSTIMEMIN(t1, t2) \
67 (DatumGetBool(DirectFunctionCall2(abstimele, \
68 AbsoluteTimeGetDatum(t1), \
69 AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
70 #define ABSTIMEMAX(t1, t2) \
71 (DatumGetBool(DirectFunctionCall2(abstimelt, \
72 AbsoluteTimeGetDatum(t1), \
73 AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
77 * Function prototypes -- internal to this file only
80 static AbsoluteTime tm2abstime(struct pg_tm * tm, int tz);
81 static void reltime2tm(RelativeTime time, struct pg_tm * tm);
82 static int istinterval(char *i_string,
83 AbsoluteTime *i_start,
88 * GetCurrentAbsoluteTime()
90 * Get the current system time (relative to Unix epoch).
93 GetCurrentAbsoluteTime(void)
98 return (AbsoluteTime) now;
103 abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
105 pg_time_t time = (pg_time_t) _time;
109 * If HasCTZSet is true then we have a brute force time zone
110 * specified. Go ahead and rotate to the local time zone since we will
111 * later bypass any calls which adjust the tm fields.
113 if (HasCTZSet && (tzp != NULL))
116 if (!HasCTZSet && tzp != NULL)
117 tx = pg_localtime(&time,global_timezone);
119 tx = pg_gmtime(&time);
121 tm->tm_year = tx->tm_year + 1900;
122 tm->tm_mon = tx->tm_mon + 1;
123 tm->tm_mday = tx->tm_mday;
124 tm->tm_hour = tx->tm_hour;
125 tm->tm_min = tx->tm_min;
126 tm->tm_sec = tx->tm_sec;
127 tm->tm_isdst = tx->tm_isdst;
129 tm->tm_gmtoff = tx->tm_gmtoff;
130 tm->tm_zone = tx->tm_zone;
135 * We have a brute force time zone per SQL99? Then use it without
136 * change since we have already rotated to the time zone.
141 tm->tm_gmtoff = CTimeZone;
149 *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
152 * XXX FreeBSD man pages indicate that this should work - tgl
158 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
159 * case it contains an error message, which doesn't fit in
162 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
163 if (strlen(tm->tm_zone) > MAXTZLEN)
165 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
166 errmsg("invalid time zone name: \"%s\"",
177 * Convert a tm structure to abstime.
178 * Note that tm has full year (not 1900-based) and 1-based month.
181 tm2abstime(struct pg_tm * tm, int tz)
186 /* validate, before going out of range on some members */
187 if (tm->tm_year < 1901 || tm->tm_year > 2038
188 || tm->tm_mon < 1 || tm->tm_mon > 12
189 || tm->tm_mday < 1 || tm->tm_mday > 31
190 || tm->tm_hour < 0 || tm->tm_hour > 23
191 || tm->tm_min < 0 || tm->tm_min > 59
192 || tm->tm_sec < 0 || tm->tm_sec > 60)
193 return INVALID_ABSTIME;
195 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
197 /* check for time out of range */
198 if (day < MIN_DAYNUM || day > MAX_DAYNUM)
199 return INVALID_ABSTIME;
201 /* convert to seconds */
202 sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
204 /* check for overflow */
205 if ((day == MAX_DAYNUM && sec < 0) ||
206 (day == MIN_DAYNUM && sec > 0))
207 return INVALID_ABSTIME;
209 /* check for reserved values (e.g. "current" on edge of usual range */
210 if (!AbsoluteTimeIsReal(sec))
211 return INVALID_ABSTIME;
218 * Decode date/time string and return abstime.
221 abstimein(PG_FUNCTION_ARGS)
223 char *str = PG_GETARG_CSTRING(0);
230 char *field[MAXDATEFIELDS];
231 char workbuf[MAXDATELEN + 1];
234 ftype[MAXDATEFIELDS];
236 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
237 field, ftype, MAXDATEFIELDS, &nf);
239 dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
241 DateTimeParseError(dterr, str, "abstime");
246 result = tm2abstime(tm, tz);
252 * Don't bother retaining this as a reserved value, but
253 * instead just set to the actual epoch time (1970-01-01)
259 result = NOEND_ABSTIME;
263 result = NOSTART_ABSTIME;
267 result = INVALID_ABSTIME;
271 elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
273 result = INVALID_ABSTIME;
277 PG_RETURN_ABSOLUTETIME(result);
282 * Given an AbsoluteTime return the English text version of the date
285 abstimeout(PG_FUNCTION_ARGS)
287 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
293 char buf[MAXDATELEN + 1];
294 char zone[MAXDATELEN + 1],
300 * Note that timestamp no longer supports 'invalid'. Retain
301 * 'invalid' for abstime for now, but dump it someday.
303 case INVALID_ABSTIME:
304 strcpy(buf, INVALID);
309 case NOSTART_ABSTIME:
313 abstime2tm(time, &tz, tm, &tzn);
314 EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
318 result = pstrdup(buf);
319 PG_RETURN_CSTRING(result);
323 * abstimerecv - converts external binary format to abstime
326 abstimerecv(PG_FUNCTION_ARGS)
328 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
330 PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
334 * abstimesend - converts abstime to binary format
337 abstimesend(PG_FUNCTION_ARGS)
339 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
342 pq_begintypsend(&buf);
343 pq_sendint(&buf, time, sizeof(time));
344 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
351 abstime_finite(PG_FUNCTION_ARGS)
353 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
355 PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
356 abstime != NOSTART_ABSTIME &&
357 abstime != NOEND_ABSTIME);
362 * abstime comparison routines
365 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
368 * We consider all INVALIDs to be equal and larger than any
369 * non-INVALID. This is somewhat arbitrary; the important thing is to
370 * have a consistent sort order.
372 if (a == INVALID_ABSTIME)
374 if (b == INVALID_ABSTIME)
375 return 0; /* INVALID = INVALID */
377 return 1; /* INVALID > non-INVALID */
380 if (b == INVALID_ABSTIME)
381 return -1; /* non-INVALID < INVALID */
392 abstimeeq(PG_FUNCTION_ARGS)
394 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
395 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
397 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
401 abstimene(PG_FUNCTION_ARGS)
403 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
404 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
406 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
410 abstimelt(PG_FUNCTION_ARGS)
412 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
413 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
415 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
419 abstimegt(PG_FUNCTION_ARGS)
421 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
422 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
424 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
428 abstimele(PG_FUNCTION_ARGS)
430 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
431 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
433 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
437 abstimege(PG_FUNCTION_ARGS)
439 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
440 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
442 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
446 btabstimecmp(PG_FUNCTION_ARGS)
448 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
449 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
451 PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
455 /* timestamp_abstime()
456 * Convert timestamp to abstime.
459 timestamp_abstime(PG_FUNCTION_ARGS)
461 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
468 if (TIMESTAMP_IS_NOBEGIN(timestamp))
469 result = NOSTART_ABSTIME;
470 else if (TIMESTAMP_IS_NOEND(timestamp))
471 result = NOEND_ABSTIME;
472 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
474 tz = DetermineLocalTimeZone(tm);
475 result = tm2abstime(tm, tz);
480 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
481 errmsg("timestamp out of range")));
482 result = INVALID_ABSTIME;
485 PG_RETURN_ABSOLUTETIME(result);
488 /* abstime_timestamp()
489 * Convert abstime to timestamp.
492 abstime_timestamp(PG_FUNCTION_ARGS)
494 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
499 char zone[MAXDATELEN + 1],
504 case INVALID_ABSTIME:
506 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507 errmsg("cannot convert abstime \"invalid\" to timestamp")));
508 TIMESTAMP_NOBEGIN(result);
511 case NOSTART_ABSTIME:
512 TIMESTAMP_NOBEGIN(result);
516 TIMESTAMP_NOEND(result);
520 abstime2tm(abstime, &tz, tm, &tzn);
521 if (tm2timestamp(tm, 0, NULL, &result) != 0)
523 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
524 errmsg("timestamp out of range")));
528 PG_RETURN_TIMESTAMP(result);
532 /* timestamptz_abstime()
533 * Convert timestamp with time zone to abstime.
536 timestamptz_abstime(PG_FUNCTION_ARGS)
538 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
544 if (TIMESTAMP_IS_NOBEGIN(timestamp))
545 result = NOSTART_ABSTIME;
546 else if (TIMESTAMP_IS_NOEND(timestamp))
547 result = NOEND_ABSTIME;
548 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
549 result = tm2abstime(tm, 0);
553 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
554 errmsg("timestamp out of range")));
555 result = INVALID_ABSTIME;
558 PG_RETURN_ABSOLUTETIME(result);
561 /* abstime_timestamptz()
562 * Convert abstime to timestamp with time zone.
565 abstime_timestamptz(PG_FUNCTION_ARGS)
567 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
572 char zone[MAXDATELEN + 1],
577 case INVALID_ABSTIME:
579 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
580 errmsg("cannot convert abstime \"invalid\" to timestamp")));
581 TIMESTAMP_NOBEGIN(result);
584 case NOSTART_ABSTIME:
585 TIMESTAMP_NOBEGIN(result);
589 TIMESTAMP_NOEND(result);
593 abstime2tm(abstime, &tz, tm, &tzn);
594 if (tm2timestamp(tm, 0, &tz, &result) != 0)
596 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
597 errmsg("timestamp out of range")));
601 PG_RETURN_TIMESTAMP(result);
605 /*****************************************************************************
606 * USER I/O ROUTINES *
607 *****************************************************************************/
610 * reltimein - converts a reltime string in an internal format
613 reltimein(PG_FUNCTION_ARGS)
615 char *str = PG_GETARG_CSTRING(0);
622 char *field[MAXDATEFIELDS];
624 ftype[MAXDATEFIELDS];
625 char workbuf[MAXDATELEN + 1];
627 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
628 field, ftype, MAXDATEFIELDS, &nf);
630 dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
633 if (dterr == DTERR_FIELD_OVERFLOW)
634 dterr = DTERR_INTERVAL_OVERFLOW;
635 DateTimeParseError(dterr, str, "reltime");
641 result = ((tm->tm_hour * 60 + tm->tm_min) * 60) + tm->tm_sec;
642 result += tm->tm_year * 36525 * 864 + ((tm->tm_mon * 30) + tm->tm_mday) * SECS_PER_DAY;
646 elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
648 result = INVALID_RELTIME;
652 PG_RETURN_RELATIVETIME(result);
656 * reltimeout - converts the internal format to a reltime string
659 reltimeout(PG_FUNCTION_ARGS)
661 RelativeTime time = PG_GETARG_RELATIVETIME(0);
665 char buf[MAXDATELEN + 1];
667 reltime2tm(time, tm);
668 EncodeInterval(tm, 0, DateStyle, buf);
670 result = pstrdup(buf);
671 PG_RETURN_CSTRING(result);
675 * reltimerecv - converts external binary format to reltime
678 reltimerecv(PG_FUNCTION_ARGS)
680 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
682 PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
686 * reltimesend - converts reltime to binary format
689 reltimesend(PG_FUNCTION_ARGS)
691 RelativeTime time = PG_GETARG_RELATIVETIME(0);
694 pq_begintypsend(&buf);
695 pq_sendint(&buf, time, sizeof(time));
696 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
701 reltime2tm(RelativeTime time, struct pg_tm * tm)
705 FMODULO(dtime, tm->tm_year, 31557600);
706 FMODULO(dtime, tm->tm_mon, 2592000);
707 FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
708 FMODULO(dtime, tm->tm_hour, 3600);
709 FMODULO(dtime, tm->tm_min, 60);
710 FMODULO(dtime, tm->tm_sec, 1);
715 * tintervalin - converts an interval string to internal format
718 tintervalin(PG_FUNCTION_ARGS)
720 char *intervalstr = PG_GETARG_CSTRING(0);
721 TimeInterval interval;
722 AbsoluteTime i_start,
727 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
729 if (istinterval(intervalstr, &t1, &t2) == 0)
731 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
732 errmsg("invalid input syntax for type tinterval: \"%s\"",
735 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
736 interval ->status = T_INTERVAL_INVAL; /* undefined */
739 interval ->status = T_INTERVAL_VALID;
741 i_start = ABSTIMEMIN(t1, t2);
742 i_end = ABSTIMEMAX(t1, t2);
743 interval ->data[0] = i_start;
744 interval ->data[1] = i_end;
746 PG_RETURN_TIMEINTERVAL(interval);
751 * tintervalout - converts an internal interval format to a string
754 tintervalout(PG_FUNCTION_ARGS)
756 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
760 i_str = (char *) palloc(T_INTERVAL_LEN); /* ["..." "..."] */
761 strcpy(i_str, "[\"");
762 if (interval->status == T_INTERVAL_INVAL)
763 strcat(i_str, INVALID_INTERVAL_STR);
766 p = DatumGetCString(DirectFunctionCall1(abstimeout,
767 AbsoluteTimeGetDatum(interval->data[0])));
770 strcat(i_str, "\" \"");
771 p = DatumGetCString(DirectFunctionCall1(abstimeout,
772 AbsoluteTimeGetDatum(interval->data[1])));
776 strcat(i_str, "\"]");
777 PG_RETURN_CSTRING(i_str);
781 * tintervalrecv - converts external binary format to tinterval
784 tintervalrecv(PG_FUNCTION_ARGS)
786 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
787 TimeInterval interval;
789 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
791 interval ->status = pq_getmsgint(buf, sizeof(interval->status));
793 if (!(interval->status == T_INTERVAL_INVAL ||
794 interval->status == T_INTERVAL_VALID))
796 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
797 errmsg("invalid status in external \"tinterval\" value")));
799 interval ->data[0] = pq_getmsgint(buf, sizeof(interval->data[0]));
800 interval ->data[1] = pq_getmsgint(buf, sizeof(interval->data[1]));
802 PG_RETURN_TIMEINTERVAL(interval);
806 * tintervalsend - converts tinterval to binary format
809 tintervalsend(PG_FUNCTION_ARGS)
811 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
814 pq_begintypsend(&buf);
815 pq_sendint(&buf, interval->status, sizeof(interval->status));
816 pq_sendint(&buf, interval->data[0], sizeof(interval->data[0]));
817 pq_sendint(&buf, interval->data[1], sizeof(interval->data[1]));
818 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
822 /*****************************************************************************
824 *****************************************************************************/
827 interval_reltime(PG_FUNCTION_ARGS)
829 Interval *interval = PG_GETARG_INTERVAL_P(0);
834 #ifdef HAVE_INT64_TIMESTAMP
841 if (interval->month == 0)
846 else if (abs(interval->month) >=12)
848 year = (interval->month / 12);
849 month = (interval->month % 12);
854 month = interval->month;
857 #ifdef HAVE_INT64_TIMESTAMP
858 span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month) *
859 INT64CONST(86400)) + interval->time;
860 span /= USECS_PER_SEC;
862 span = (365.25 * year + 30.0 * month) * SECS_PER_DAY + interval->time;
865 if (span < INT_MIN || span > INT_MAX)
866 time = INVALID_RELTIME;
870 PG_RETURN_RELATIVETIME(time);
875 reltime_interval(PG_FUNCTION_ARGS)
877 RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
882 result = (Interval *) palloc(sizeof(Interval));
886 case INVALID_RELTIME:
888 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
889 errmsg("cannot convert reltime \"invalid\" to interval")));
895 #ifdef HAVE_INT64_TIMESTAMP
896 year = (reltime / (36525 * 864));
897 reltime -= (year * (36525 * 864));
898 month = (reltime / (30 * SECS_PER_DAY));
899 reltime -= (month * (30 * SECS_PER_DAY));
901 result->time = (reltime * USECS_PER_SEC);
903 TMODULO(reltime, year, 36525 * 864);
904 TMODULO(reltime, month, 30 * SECS_PER_DAY);
906 result->time = reltime;
908 result->month = 12 * year + month;
912 PG_RETURN_INTERVAL_P(result);
917 * mktinterval - creates a time interval with endpoints t1 and t2
920 mktinterval(PG_FUNCTION_ARGS)
922 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
923 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
924 AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
925 AbsoluteTime tend = ABSTIMEMAX(t1, t2);
926 TimeInterval interval;
928 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
930 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
931 interval ->status = T_INTERVAL_INVAL;
935 interval ->status = T_INTERVAL_VALID;
936 interval ->data[0] = tstart;
937 interval ->data[1] = tend;
940 PG_RETURN_TIMEINTERVAL(interval);
944 * timepl, timemi and abstimemi use the formula
945 * abstime + reltime = abstime
946 * so abstime - reltime = abstime
947 * and abstime - abstime = reltime
951 * timepl - returns the value of (abstime t1 + reltime t2)
954 timepl(PG_FUNCTION_ARGS)
956 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
957 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
959 if (AbsoluteTimeIsReal(t1) &&
960 RelativeTimeIsValid(t2) &&
961 ((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
962 (t2 <= 0 && t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
963 PG_RETURN_ABSOLUTETIME(t1 + t2);
965 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
970 * timemi - returns the value of (abstime t1 - reltime t2)
973 timemi(PG_FUNCTION_ARGS)
975 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
976 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
978 if (AbsoluteTimeIsReal(t1) &&
979 RelativeTimeIsValid(t2) &&
980 ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
981 (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
982 PG_RETURN_ABSOLUTETIME(t1 - t2);
984 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
989 * intinterval - returns true iff absolute date is in the interval
992 intinterval(PG_FUNCTION_ARGS)
994 AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
995 TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
997 if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
999 if (DatumGetBool(DirectFunctionCall2(abstimege,
1000 AbsoluteTimeGetDatum(t),
1001 AbsoluteTimeGetDatum(interval->data[0]))) &&
1002 DatumGetBool(DirectFunctionCall2(abstimele,
1003 AbsoluteTimeGetDatum(t),
1004 AbsoluteTimeGetDatum(interval->data[1]))))
1005 PG_RETURN_BOOL(true);
1007 PG_RETURN_BOOL(false);
1011 * tintervalrel - returns relative time corresponding to interval
1014 tintervalrel(PG_FUNCTION_ARGS)
1016 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1017 AbsoluteTime t1 = interval->data[0];
1018 AbsoluteTime t2 = interval->data[1];
1020 if (interval->status != T_INTERVAL_VALID)
1021 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1023 if (AbsoluteTimeIsReal(t1) &&
1024 AbsoluteTimeIsReal(t2))
1025 PG_RETURN_RELATIVETIME(t2 - t1);
1027 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1032 * timenow - returns time "now", internal format
1034 * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1037 timenow(PG_FUNCTION_ARGS)
1042 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1044 PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1048 * reltime comparison routines
1051 reltime_cmp_internal(RelativeTime a, RelativeTime b)
1054 * We consider all INVALIDs to be equal and larger than any
1055 * non-INVALID. This is somewhat arbitrary; the important thing is to
1056 * have a consistent sort order.
1058 if (a == INVALID_RELTIME)
1060 if (b == INVALID_RELTIME)
1061 return 0; /* INVALID = INVALID */
1063 return 1; /* INVALID > non-INVALID */
1066 if (b == INVALID_RELTIME)
1067 return -1; /* non-INVALID < INVALID */
1078 reltimeeq(PG_FUNCTION_ARGS)
1080 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1081 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1083 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1087 reltimene(PG_FUNCTION_ARGS)
1089 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1090 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1092 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1096 reltimelt(PG_FUNCTION_ARGS)
1098 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1099 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1101 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1105 reltimegt(PG_FUNCTION_ARGS)
1107 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1108 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1110 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1114 reltimele(PG_FUNCTION_ARGS)
1116 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1117 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1119 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1123 reltimege(PG_FUNCTION_ARGS)
1125 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1126 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1128 PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
1132 btreltimecmp(PG_FUNCTION_ARGS)
1134 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1135 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1137 PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1142 * tintervalsame - returns true iff interval i1 is same as interval i2
1143 * Check begin and end time.
1146 tintervalsame(PG_FUNCTION_ARGS)
1148 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1149 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1151 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1152 PG_RETURN_BOOL(false);
1154 if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1155 AbsoluteTimeGetDatum(i1->data[0]),
1156 AbsoluteTimeGetDatum(i2->data[0]))) &&
1157 DatumGetBool(DirectFunctionCall2(abstimeeq,
1158 AbsoluteTimeGetDatum(i1->data[1]),
1159 AbsoluteTimeGetDatum(i2->data[1]))))
1160 PG_RETURN_BOOL(true);
1161 PG_RETURN_BOOL(false);
1165 * tinterval comparison routines
1167 * Note: comparison is based on the lengths of the intervals, not on
1168 * endpoint value. This is pretty bogus, but since it's only a legacy
1169 * datatype I'm not going to propose changing it.
1172 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1180 * We consider all INVALIDs to be equal and larger than any
1181 * non-INVALID. This is somewhat arbitrary; the important thing is to
1182 * have a consistent sort order.
1184 a_invalid = a->status == T_INTERVAL_INVAL ||
1185 a->data[0] == INVALID_ABSTIME ||
1186 a->data[1] == INVALID_ABSTIME;
1187 b_invalid = b->status == T_INTERVAL_INVAL ||
1188 b->data[0] == INVALID_ABSTIME ||
1189 b->data[1] == INVALID_ABSTIME;
1194 return 0; /* INVALID = INVALID */
1196 return 1; /* INVALID > non-INVALID */
1200 return -1; /* non-INVALID < INVALID */
1202 a_len = a->data[1] - a->data[0];
1203 b_len = b->data[1] - b->data[0];
1207 else if (a_len == b_len)
1214 tintervaleq(PG_FUNCTION_ARGS)
1216 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1217 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1219 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
1223 tintervalne(PG_FUNCTION_ARGS)
1225 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1226 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1228 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1232 tintervallt(PG_FUNCTION_ARGS)
1234 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1235 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1237 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1241 tintervalle(PG_FUNCTION_ARGS)
1243 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1244 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1246 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1250 tintervalgt(PG_FUNCTION_ARGS)
1252 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1253 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1255 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1259 tintervalge(PG_FUNCTION_ARGS)
1261 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1262 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1264 PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
1268 bttintervalcmp(PG_FUNCTION_ARGS)
1270 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1271 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1273 PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1278 * tintervalleneq - returns true iff length of interval i is equal to
1280 * tintervallenne - returns true iff length of interval i is not equal
1282 * tintervallenlt - returns true iff length of interval i is less than
1284 * tintervallengt - returns true iff length of interval i is greater
1286 * tintervallenle - returns true iff length of interval i is less or
1287 * equal than reltime t
1288 * tintervallenge - returns true iff length of interval i is greater or
1289 * equal than reltime t
1292 tintervalleneq(PG_FUNCTION_ARGS)
1294 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1295 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1298 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1299 PG_RETURN_BOOL(false);
1300 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1301 TimeIntervalGetDatum(i)));
1302 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1306 tintervallenne(PG_FUNCTION_ARGS)
1308 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1309 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1312 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1313 PG_RETURN_BOOL(false);
1314 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1315 TimeIntervalGetDatum(i)));
1316 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1320 tintervallenlt(PG_FUNCTION_ARGS)
1322 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1323 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1326 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1327 PG_RETURN_BOOL(false);
1328 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1329 TimeIntervalGetDatum(i)));
1330 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1334 tintervallengt(PG_FUNCTION_ARGS)
1336 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1337 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1340 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1341 PG_RETURN_BOOL(false);
1342 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1343 TimeIntervalGetDatum(i)));
1344 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1348 tintervallenle(PG_FUNCTION_ARGS)
1350 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1351 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1354 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1355 PG_RETURN_BOOL(false);
1356 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1357 TimeIntervalGetDatum(i)));
1358 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1362 tintervallenge(PG_FUNCTION_ARGS)
1364 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1365 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1368 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1369 PG_RETURN_BOOL(false);
1370 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1371 TimeIntervalGetDatum(i)));
1372 PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1376 * tintervalct - returns true iff interval i1 contains interval i2
1379 tintervalct(PG_FUNCTION_ARGS)
1381 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1382 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1384 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1385 PG_RETURN_BOOL(false);
1386 if (DatumGetBool(DirectFunctionCall2(abstimele,
1387 AbsoluteTimeGetDatum(i1->data[0]),
1388 AbsoluteTimeGetDatum(i2->data[0]))) &&
1389 DatumGetBool(DirectFunctionCall2(abstimege,
1390 AbsoluteTimeGetDatum(i1->data[1]),
1391 AbsoluteTimeGetDatum(i2->data[1]))))
1392 PG_RETURN_BOOL(true);
1393 PG_RETURN_BOOL(false);
1397 * tintervalov - returns true iff interval i1 (partially) overlaps i2
1400 tintervalov(PG_FUNCTION_ARGS)
1402 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1403 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1405 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1406 PG_RETURN_BOOL(false);
1407 if (DatumGetBool(DirectFunctionCall2(abstimelt,
1408 AbsoluteTimeGetDatum(i1->data[1]),
1409 AbsoluteTimeGetDatum(i2->data[0]))) ||
1410 DatumGetBool(DirectFunctionCall2(abstimegt,
1411 AbsoluteTimeGetDatum(i1->data[0]),
1412 AbsoluteTimeGetDatum(i2->data[1]))))
1413 PG_RETURN_BOOL(false);
1414 PG_RETURN_BOOL(true);
1418 * tintervalstart - returns the start of interval i
1421 tintervalstart(PG_FUNCTION_ARGS)
1423 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1425 if (i->status == T_INTERVAL_INVAL)
1426 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1427 PG_RETURN_ABSOLUTETIME(i->data[0]);
1431 * tintervalend - returns the end of interval i
1434 tintervalend(PG_FUNCTION_ARGS)
1436 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1438 if (i->status == T_INTERVAL_INVAL)
1439 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1440 PG_RETURN_ABSOLUTETIME(i->data[1]);
1444 /*****************************************************************************
1445 * PRIVATE ROUTINES *
1446 *****************************************************************************/
1449 * istinterval - returns 1, iff i_string is a valid interval descr.
1450 * 0, iff i_string is NOT a valid interval desc.
1451 * 2, iff any time is INVALID_ABSTIME
1454 * i_start, i_end: interval margins
1457 * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1459 * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
1461 * where <AbsTime> satisfies the syntax of absolute time.
1463 * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
1466 istinterval(char *i_string,
1467 AbsoluteTime *i_start,
1468 AbsoluteTime *i_end)
1475 /* skip leading blanks up to '[' */
1476 while ((c = *p) != '\0')
1481 return 0; /* syntax error */
1486 /* skip leading blanks up to '"' */
1487 while ((c = *p) != '\0')
1492 return 0; /* syntax error */
1497 if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1498 return 0; /* undefined range, handled like a syntax
1500 /* search for the end of the first date and change it to a NULL */
1502 while ((c = *p1) != '\0')
1511 /* get the first date */
1512 *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1513 CStringGetDatum(p)));
1514 /* rechange NULL at the end of the first date to a '"' */
1517 /* skip blanks up to '"', beginning of second date */
1518 while ((c = *p) != '\0')
1523 return 0; /* syntax error */
1528 /* search for the end of the second date and change it to a NULL */
1530 while ((c = *p1) != '\0')
1539 /* get the second date */
1540 *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1541 CStringGetDatum(p)));
1542 /* rechange NULL at the end of the first date to a '"' */
1545 /* skip blanks up to ']' */
1546 while ((c = *p) != '\0')
1551 return 0; /* syntax error */
1558 return 0; /* syntax error */
1559 /* it seems to be a valid interval */
1564 /*****************************************************************************
1566 *****************************************************************************/
1570 * returns the current time as a text. similar to timenow() but returns
1571 * seconds with more precision (up to microsecs). (I need this to compare
1572 * the Wisconsin benchmark with Illustra whose TimeNow() shows current
1573 * time with precision up to microsecs.) - ay 3/95
1576 timeofday(PG_FUNCTION_ARGS)
1579 struct timezone tpz;
1586 gettimeofday(&tp, &tpz);
1587 tt = (pg_time_t) tp.tv_sec;
1588 pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1589 pg_localtime(&tt,global_timezone));
1590 snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1592 len = VARHDRSZ + strlen(buf);
1593 result = (text *) palloc(len);
1594 VARATT_SIZEP(result) = len;
1595 memcpy(VARDATA(result), buf, strlen(buf));
1596 PG_RETURN_TEXT_P(result);