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-2002, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.111 2003/07/28 00:09:16 tgl Exp $
15 *-------------------------------------------------------------------------
25 #include "access/xact.h"
26 #include "libpq/pqformat.h"
27 #include "miscadmin.h"
28 #include "utils/builtins.h"
31 #define MIN_DAYNUM -24856 /* December 13, 1901 */
32 #define MAX_DAYNUM 24854 /* January 18, 2038 */
34 #define INVALID_RELTIME_STR "Undefined RelTime"
35 #define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
36 #define RELTIME_LABEL '@'
37 #define RELTIME_PAST "ago"
38 #define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
41 * Unix epoch is Jan 1 00:00:00 1970.
42 * Postgres knows about times sixty-eight years on either side of that
43 * for these 4-byte types.
45 * "tinterval" is two 4-byte fields.
46 * Definitions for parsing tinterval.
49 #define IsSpace(C) ((C) == ' ')
51 #define T_INTERVAL_INVAL 0 /* data represents no valid interval */
52 #define T_INTERVAL_VALID 1 /* data represents a valid interval */
54 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
56 * 1234567890123456789012345678901234567890123456789012345678901234
58 * we allocate some extra -- timezones are usually 3 characters but
59 * this is not in the POSIX standard...
61 #define T_INTERVAL_LEN 80
62 #define INVALID_INTERVAL_STR "Undefined Range"
63 #define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
65 #define ABSTIMEMIN(t1, t2) \
66 (DatumGetBool(DirectFunctionCall2(abstimele, \
67 AbsoluteTimeGetDatum(t1), \
68 AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
69 #define ABSTIMEMAX(t1, t2) \
70 (DatumGetBool(DirectFunctionCall2(abstimelt, \
71 AbsoluteTimeGetDatum(t1), \
72 AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
76 * Function prototypes -- internal to this file only
79 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
80 static void reltime2tm(RelativeTime time, struct tm * tm);
81 static int istinterval(char *i_string,
82 AbsoluteTime *i_start,
87 * GetCurrentAbsoluteTime()
89 * Get the current system time (relative to Unix epoch).
92 GetCurrentAbsoluteTime(void)
97 return (AbsoluteTime) now;
102 * GetCurrentAbsoluteTimeUsec()
104 * Get the current system time (relative to Unix epoch), including fractional
105 * seconds expressed as microseconds.
108 GetCurrentAbsoluteTimeUsec(int *usec)
113 gettimeofday(&tp, NULL);
116 return (AbsoluteTime) now;
121 * AbsoluteTimeUsecToTimestampTz()
123 * Convert system time including microseconds to TimestampTz representation.
126 AbsoluteTimeUsecToTimestampTz(AbsoluteTime sec, int usec)
130 #ifdef HAVE_INT64_TIMESTAMP
131 result = ((sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400))
132 * INT64CONST(1000000)) + usec;
134 result = sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * 86400)
135 + (usec / 1000000.0);
143 * GetCurrentDateTime()
145 * Get the transaction start time ("now()") broken down as a struct tm.
148 GetCurrentDateTime(struct tm * tm)
152 abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
156 * GetCurrentTimeUsec()
158 * Get the transaction start time ("now()") broken down as a struct tm,
159 * including fractional seconds and timezone offset.
162 GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec, int *tzp)
167 abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
168 /* Note: don't pass NULL tzp to abstime2tm; affects behavior */
171 #ifdef HAVE_INT64_TIMESTAMP
174 *fsec = usec / 1000000.0;
180 abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
182 time_t time = (time_t) _time;
186 * If HasCTZSet is true then we have a brute force time zone
187 * specified. Go ahead and rotate to the local time zone since we will
188 * later bypass any calls which adjust the tm fields.
190 if (HasCTZSet && (tzp != NULL))
193 if ((!HasCTZSet) && (tzp != NULL))
194 tx = localtime((time_t *) &time);
196 tx = gmtime((time_t *) &time);
198 tm->tm_year = tx->tm_year + 1900;
199 tm->tm_mon = tx->tm_mon + 1;
200 tm->tm_mday = tx->tm_mday;
201 tm->tm_hour = tx->tm_hour;
202 tm->tm_min = tx->tm_min;
203 tm->tm_sec = tx->tm_sec;
204 tm->tm_isdst = tx->tm_isdst;
206 #if defined(HAVE_TM_ZONE)
207 tm->tm_gmtoff = tx->tm_gmtoff;
208 tm->tm_zone = tx->tm_zone;
213 * We have a brute force time zone per SQL99? Then use it without
214 * change since we have already rotated to the time zone.
219 tm->tm_gmtoff = CTimeZone;
227 *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
230 * XXX FreeBSD man pages indicate that this should work - tgl
236 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
237 * case it contains an error message, which doesn't fit in
240 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
241 if (strlen(tm->tm_zone) > MAXTZLEN)
243 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
244 errmsg("invalid timezone name: \"%s\"",
251 #elif defined(HAVE_INT_TIMEZONE)
255 * We have a brute force time zone per SQL99? Then use it without
256 * change since we have already rotated to the time zone.
267 *tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
272 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
273 * case it contains an error message, which doesn't fit in
276 StrNCpy(*tzn, tzname[tm->tm_isdst], MAXTZLEN + 1);
277 if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)
279 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
280 errmsg("invalid timezone name: \"%s\"",
281 tzname[tm->tm_isdst])));
287 #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
291 * We have a brute force time zone per SQL99? Then use it without
292 * change since we have already rotated to the time zone.
315 * Convert a tm structure to abstime.
316 * Note that tm has full year (not 1900-based) and 1-based month.
319 tm2abstime(struct tm * tm, int tz)
324 /* validate, before going out of range on some members */
325 if (tm->tm_year < 1901 || tm->tm_year > 2038
326 || tm->tm_mon < 1 || tm->tm_mon > 12
327 || tm->tm_mday < 1 || tm->tm_mday > 31
328 || tm->tm_hour < 0 || tm->tm_hour > 23
329 || tm->tm_min < 0 || tm->tm_min > 59
330 || tm->tm_sec < 0 || tm->tm_sec > 60)
331 return INVALID_ABSTIME;
333 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
335 /* check for time out of range */
336 if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
337 return INVALID_ABSTIME;
339 /* convert to seconds */
340 sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
342 /* check for overflow */
343 if ((day == MAX_DAYNUM && sec < 0) ||
344 (day == MIN_DAYNUM && sec > 0))
345 return INVALID_ABSTIME;
347 /* check for reserved values (e.g. "current" on edge of usual range */
348 if (!AbsoluteTimeIsReal(sec))
349 return INVALID_ABSTIME;
356 * Decode date/time string and return abstime.
359 abstimein(PG_FUNCTION_ARGS)
361 char *str = PG_GETARG_CSTRING(0);
367 char *field[MAXDATEFIELDS];
368 char lowstr[MAXDATELEN + 1];
371 ftype[MAXDATEFIELDS];
373 if (strlen(str) >= sizeof(lowstr))
375 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
376 errmsg("invalid input syntax for abstime: \"%s\"", str)));
378 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
379 || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
381 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
382 errmsg("invalid input syntax for abstime: \"%s\"", str)));
387 result = tm2abstime(tm, tz);
393 * Don't bother retaining this as a reserved value, but
394 * instead just set to the actual epoch time (1970-01-01)
400 result = NOEND_ABSTIME;
404 result = NOSTART_ABSTIME;
408 result = INVALID_ABSTIME;
412 elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
414 result = INVALID_ABSTIME;
418 PG_RETURN_ABSOLUTETIME(result);
423 * Given an AbsoluteTime return the English text version of the date
426 abstimeout(PG_FUNCTION_ARGS)
428 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
434 char buf[MAXDATELEN + 1];
435 char zone[MAXDATELEN + 1],
441 * Note that timestamp no longer supports 'invalid'. Retain
442 * 'invalid' for abstime for now, but dump it someday.
444 case INVALID_ABSTIME:
445 strcpy(buf, INVALID);
450 case NOSTART_ABSTIME:
454 abstime2tm(time, &tz, tm, &tzn);
455 EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
459 result = pstrdup(buf);
460 PG_RETURN_CSTRING(result);
464 * abstimerecv - converts external binary format to abstime
467 abstimerecv(PG_FUNCTION_ARGS)
469 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
471 PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
475 * abstimesend - converts abstime to binary format
478 abstimesend(PG_FUNCTION_ARGS)
480 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
483 pq_begintypsend(&buf);
484 pq_sendint(&buf, time, sizeof(time));
485 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
492 abstime_finite(PG_FUNCTION_ARGS)
494 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
496 PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&
497 (abstime != NOSTART_ABSTIME) &&
498 (abstime != NOEND_ABSTIME));
503 * abstime comparison routines
506 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
509 * We consider all INVALIDs to be equal and larger than any non-INVALID.
510 * This is somewhat arbitrary; the important thing is to have a
511 * consistent sort order.
513 if (a == INVALID_ABSTIME)
515 if (b == INVALID_ABSTIME)
516 return 0; /* INVALID = INVALID */
518 return 1; /* INVALID > non-INVALID */
521 if (b == INVALID_ABSTIME)
522 return -1; /* non-INVALID < INVALID */
525 /* CURRENT is no longer stored internally... */
526 /* XXX this is broken, should go away: */
527 if (a == CURRENT_ABSTIME)
528 a = GetCurrentTransactionStartTime();
529 if (b == CURRENT_ABSTIME)
530 b = GetCurrentTransactionStartTime();
542 abstimeeq(PG_FUNCTION_ARGS)
544 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
545 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
547 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
551 abstimene(PG_FUNCTION_ARGS)
553 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
554 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
556 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
560 abstimelt(PG_FUNCTION_ARGS)
562 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
563 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
565 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
569 abstimegt(PG_FUNCTION_ARGS)
571 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
572 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
574 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
578 abstimele(PG_FUNCTION_ARGS)
580 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
581 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
583 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
587 abstimege(PG_FUNCTION_ARGS)
589 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
590 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
592 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
596 btabstimecmp(PG_FUNCTION_ARGS)
598 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
599 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
601 PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
605 /* timestamp_abstime()
606 * Convert timestamp to abstime.
609 timestamp_abstime(PG_FUNCTION_ARGS)
611 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
618 if (TIMESTAMP_IS_NOBEGIN(timestamp))
619 result = NOSTART_ABSTIME;
620 else if (TIMESTAMP_IS_NOEND(timestamp))
621 result = NOEND_ABSTIME;
622 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
624 tz = DetermineLocalTimeZone(tm);
625 result = tm2abstime(tm, tz);
630 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
631 errmsg("timestamp out of range")));
632 result = INVALID_ABSTIME;
635 PG_RETURN_ABSOLUTETIME(result);
638 /* abstime_timestamp()
639 * Convert abstime to timestamp.
642 abstime_timestamp(PG_FUNCTION_ARGS)
644 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
649 char zone[MAXDATELEN + 1],
654 case INVALID_ABSTIME:
656 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
657 errmsg("cannot convert \"invalid\" abstime to timestamp")));
658 TIMESTAMP_NOBEGIN(result);
661 case NOSTART_ABSTIME:
662 TIMESTAMP_NOBEGIN(result);
666 TIMESTAMP_NOEND(result);
670 abstime2tm(abstime, &tz, tm, &tzn);
671 if (tm2timestamp(tm, 0, NULL, &result) != 0)
673 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
674 errmsg("timestamp out of range")));
678 PG_RETURN_TIMESTAMP(result);
682 /* timestamptz_abstime()
683 * Convert timestamp with time zone to abstime.
686 timestamptz_abstime(PG_FUNCTION_ARGS)
688 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
694 if (TIMESTAMP_IS_NOBEGIN(timestamp))
695 result = NOSTART_ABSTIME;
696 else if (TIMESTAMP_IS_NOEND(timestamp))
697 result = NOEND_ABSTIME;
698 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
699 result = tm2abstime(tm, 0);
703 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
704 errmsg("timestamp out of range")));
705 result = INVALID_ABSTIME;
708 PG_RETURN_ABSOLUTETIME(result);
711 /* abstime_timestamptz()
712 * Convert abstime to timestamp with time zone.
715 abstime_timestamptz(PG_FUNCTION_ARGS)
717 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
722 char zone[MAXDATELEN + 1],
727 case INVALID_ABSTIME:
729 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
730 errmsg("cannot convert \"invalid\" abstime to timestamp")));
731 TIMESTAMP_NOBEGIN(result);
734 case NOSTART_ABSTIME:
735 TIMESTAMP_NOBEGIN(result);
739 TIMESTAMP_NOEND(result);
743 abstime2tm(abstime, &tz, tm, &tzn);
744 if (tm2timestamp(tm, 0, &tz, &result) != 0)
746 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
747 errmsg("timestamp out of range")));
751 PG_RETURN_TIMESTAMP(result);
755 /*****************************************************************************
756 * USER I/O ROUTINES *
757 *****************************************************************************/
760 * reltimein - converts a reltime string in an internal format
763 reltimein(PG_FUNCTION_ARGS)
765 char *str = PG_GETARG_CSTRING(0);
771 char *field[MAXDATEFIELDS];
773 ftype[MAXDATEFIELDS];
774 char lowstr[MAXDATELEN + 1];
776 if (strlen(str) >= sizeof(lowstr))
778 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
779 errmsg("invalid input syntax for reltime: \"%s\"", str)));
781 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
782 || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
784 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
785 errmsg("invalid input syntax for reltime: \"%s\"", str)));
790 result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
791 result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
795 elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
797 result = INVALID_RELTIME;
801 PG_RETURN_RELATIVETIME(result);
805 * reltimeout - converts the internal format to a reltime string
808 reltimeout(PG_FUNCTION_ARGS)
810 RelativeTime time = PG_GETARG_RELATIVETIME(0);
814 char buf[MAXDATELEN + 1];
816 reltime2tm(time, tm);
817 EncodeInterval(tm, 0, DateStyle, buf);
819 result = pstrdup(buf);
820 PG_RETURN_CSTRING(result);
824 * reltimerecv - converts external binary format to reltime
827 reltimerecv(PG_FUNCTION_ARGS)
829 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
831 PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
835 * reltimesend - converts reltime to binary format
838 reltimesend(PG_FUNCTION_ARGS)
840 RelativeTime time = PG_GETARG_RELATIVETIME(0);
843 pq_begintypsend(&buf);
844 pq_sendint(&buf, time, sizeof(time));
845 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
850 reltime2tm(RelativeTime time, struct tm * tm)
854 FMODULO(dtime, tm->tm_year, 31557600);
855 FMODULO(dtime, tm->tm_mon, 2592000);
856 FMODULO(dtime, tm->tm_mday, 86400);
857 FMODULO(dtime, tm->tm_hour, 3600);
858 FMODULO(dtime, tm->tm_min, 60);
859 FMODULO(dtime, tm->tm_sec, 1);
864 * tintervalin - converts an interval string to internal format
867 tintervalin(PG_FUNCTION_ARGS)
869 char *intervalstr = PG_GETARG_CSTRING(0);
870 TimeInterval interval;
871 AbsoluteTime i_start,
876 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
877 if (istinterval(intervalstr, &t1, &t2) == 0)
879 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
880 errmsg("invalid input syntax for tinterval: \"%s\"",
883 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
884 interval->status = T_INTERVAL_INVAL; /* undefined */
886 interval->status = T_INTERVAL_VALID;
888 i_start = ABSTIMEMIN(t1, t2);
889 i_end = ABSTIMEMAX(t1, t2);
890 interval->data[0] = i_start;
891 interval->data[1] = i_end;
893 PG_RETURN_TIMEINTERVAL(interval);
898 * tintervalout - converts an internal interval format to a string
901 tintervalout(PG_FUNCTION_ARGS)
903 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
907 i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
908 strcpy(i_str, "[\"");
909 if (interval->status == T_INTERVAL_INVAL)
910 strcat(i_str, INVALID_INTERVAL_STR);
913 p = DatumGetCString(DirectFunctionCall1(abstimeout,
914 AbsoluteTimeGetDatum(interval->data[0])));
917 strcat(i_str, "\" \"");
918 p = DatumGetCString(DirectFunctionCall1(abstimeout,
919 AbsoluteTimeGetDatum(interval->data[1])));
923 strcat(i_str, "\"]\0");
924 PG_RETURN_CSTRING(i_str);
928 * tintervalrecv - converts external binary format to tinterval
931 tintervalrecv(PG_FUNCTION_ARGS)
933 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
934 TimeInterval interval;
936 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
938 interval->status = pq_getmsgint(buf, sizeof(interval->status));
939 if (!(interval->status == T_INTERVAL_INVAL ||
940 interval->status == T_INTERVAL_VALID))
942 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
943 errmsg("invalid status in external tinterval")));
945 interval->data[0] = pq_getmsgint(buf, sizeof(interval->data[0]));
946 interval->data[1] = pq_getmsgint(buf, sizeof(interval->data[1]));
948 PG_RETURN_TIMEINTERVAL(interval);
952 * tintervalsend - converts tinterval to binary format
955 tintervalsend(PG_FUNCTION_ARGS)
957 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
960 pq_begintypsend(&buf);
961 pq_sendint(&buf, interval->status, sizeof(interval->status));
962 pq_sendint(&buf, interval->data[0], sizeof(interval->data[0]));
963 pq_sendint(&buf, interval->data[1], sizeof(interval->data[1]));
964 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
968 /*****************************************************************************
970 *****************************************************************************/
973 interval_reltime(PG_FUNCTION_ARGS)
975 Interval *interval = PG_GETARG_INTERVAL_P(0);
980 #ifdef HAVE_INT64_TIMESTAMP
987 if (interval->month == 0)
992 else if (abs(interval->month) >= 12)
994 year = (interval->month / 12);
995 month = (interval->month % 12);
1000 month = interval->month;
1003 #ifdef HAVE_INT64_TIMESTAMP
1004 span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
1005 * INT64CONST(86400)) + interval->time);
1006 span /= INT64CONST(1000000);
1008 span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
1011 if ((span < INT_MIN) || (span > INT_MAX))
1012 time = INVALID_RELTIME;
1016 PG_RETURN_RELATIVETIME(time);
1021 reltime_interval(PG_FUNCTION_ARGS)
1023 RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
1028 result = (Interval *) palloc(sizeof(Interval));
1032 case INVALID_RELTIME:
1034 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1035 errmsg("cannot convert \"invalid\" reltime to interval")));
1041 #ifdef HAVE_INT64_TIMESTAMP
1042 year = (reltime / (36525 * 864));
1043 reltime -= (year * (36525 * 864));
1044 month = (reltime / (30 * 86400));
1045 reltime -= (month * (30 * 86400));
1047 result->time = (reltime * INT64CONST(1000000));
1049 TMODULO(reltime, year, (36525 * 864));
1050 TMODULO(reltime, month, (30 * 86400));
1052 result->time = reltime;
1054 result->month = ((12 * year) + month);
1058 PG_RETURN_INTERVAL_P(result);
1063 * mktinterval - creates a time interval with endpoints t1 and t2
1066 mktinterval(PG_FUNCTION_ARGS)
1068 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1069 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
1070 AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
1071 AbsoluteTime tend = ABSTIMEMAX(t1, t2);
1072 TimeInterval interval;
1074 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
1076 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1077 interval->status = T_INTERVAL_INVAL;
1080 interval->status = T_INTERVAL_VALID;
1081 interval->data[0] = tstart;
1082 interval->data[1] = tend;
1085 PG_RETURN_TIMEINTERVAL(interval);
1089 * timepl, timemi and abstimemi use the formula
1090 * abstime + reltime = abstime
1091 * so abstime - reltime = abstime
1092 * and abstime - abstime = reltime
1096 * timepl - returns the value of (abstime t1 + reltime t2)
1099 timepl(PG_FUNCTION_ARGS)
1101 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1102 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1104 if (AbsoluteTimeIsReal(t1) &&
1105 RelativeTimeIsValid(t2) &&
1106 ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
1107 : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
1108 PG_RETURN_ABSOLUTETIME(t1 + t2);
1110 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1115 * timemi - returns the value of (abstime t1 - reltime t2)
1118 timemi(PG_FUNCTION_ARGS)
1120 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1121 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1123 if (AbsoluteTimeIsReal(t1) &&
1124 RelativeTimeIsValid(t2) &&
1125 ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
1126 : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
1127 PG_RETURN_ABSOLUTETIME(t1 - t2);
1129 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1134 * intinterval - returns true iff absolute date is in the interval
1137 intinterval(PG_FUNCTION_ARGS)
1139 AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
1140 TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
1142 if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1144 if (DatumGetBool(DirectFunctionCall2(abstimege,
1145 AbsoluteTimeGetDatum(t),
1146 AbsoluteTimeGetDatum(interval->data[0]))) &&
1147 DatumGetBool(DirectFunctionCall2(abstimele,
1148 AbsoluteTimeGetDatum(t),
1149 AbsoluteTimeGetDatum(interval->data[1]))))
1150 PG_RETURN_BOOL(true);
1152 PG_RETURN_BOOL(false);
1156 * tintervalrel - returns relative time corresponding to interval
1159 tintervalrel(PG_FUNCTION_ARGS)
1161 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1162 AbsoluteTime t1 = interval->data[0];
1163 AbsoluteTime t2 = interval->data[1];
1165 if (interval->status != T_INTERVAL_VALID)
1166 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1168 if (AbsoluteTimeIsReal(t1) &&
1169 AbsoluteTimeIsReal(t2))
1170 PG_RETURN_RELATIVETIME(t2 - t1);
1172 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1177 * timenow - returns time "now", internal format
1179 * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1182 timenow(PG_FUNCTION_ARGS)
1187 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1189 PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1193 * reltimeeq - returns true iff arguments are equal
1194 * reltimene - returns true iff arguments are not equal
1195 * reltimelt - returns true iff t1 less than t2
1196 * reltimegt - returns true iff t1 greater than t2
1197 * reltimele - returns true iff t1 less than or equal to t2
1198 * reltimege - returns true iff t1 greater than or equal to t2
1201 reltimeeq(PG_FUNCTION_ARGS)
1203 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1204 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1206 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1207 PG_RETURN_BOOL(false);
1208 PG_RETURN_BOOL(t1 == t2);
1212 reltimene(PG_FUNCTION_ARGS)
1214 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1215 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1217 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1218 PG_RETURN_BOOL(false);
1219 PG_RETURN_BOOL(t1 != t2);
1223 reltimelt(PG_FUNCTION_ARGS)
1225 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1226 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1228 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1229 PG_RETURN_BOOL(false);
1230 PG_RETURN_BOOL(t1 < t2);
1234 reltimegt(PG_FUNCTION_ARGS)
1236 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1237 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1239 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1240 PG_RETURN_BOOL(false);
1241 PG_RETURN_BOOL(t1 > t2);
1245 reltimele(PG_FUNCTION_ARGS)
1247 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1248 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1250 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1251 PG_RETURN_BOOL(false);
1252 PG_RETURN_BOOL(t1 <= t2);
1256 reltimege(PG_FUNCTION_ARGS)
1258 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1259 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1261 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1262 PG_RETURN_BOOL(false);
1263 PG_RETURN_BOOL(t1 >= t2);
1268 * tintervalsame - returns true iff interval i1 is same as interval i2
1269 * Check begin and end time.
1272 tintervalsame(PG_FUNCTION_ARGS)
1274 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1275 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1277 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1278 PG_RETURN_BOOL(false);
1280 if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1281 AbsoluteTimeGetDatum(i1->data[0]),
1282 AbsoluteTimeGetDatum(i2->data[0]))) &&
1283 DatumGetBool(DirectFunctionCall2(abstimeeq,
1284 AbsoluteTimeGetDatum(i1->data[1]),
1285 AbsoluteTimeGetDatum(i2->data[1]))))
1286 PG_RETURN_BOOL(true);
1287 PG_RETURN_BOOL(false);
1292 * tintervaleq - returns true iff interval i1 is equal to interval i2
1293 * Check length of intervals.
1296 tintervaleq(PG_FUNCTION_ARGS)
1298 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1299 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1305 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1306 PG_RETURN_BOOL(false);
1313 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1314 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1315 PG_RETURN_BOOL(false);
1317 PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
1321 tintervalne(PG_FUNCTION_ARGS)
1323 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1324 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1330 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1331 PG_RETURN_BOOL(false);
1338 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1339 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1340 PG_RETURN_BOOL(false);
1342 PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
1346 tintervallt(PG_FUNCTION_ARGS)
1348 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1349 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1355 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1356 PG_RETURN_BOOL(false);
1363 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1364 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1365 PG_RETURN_BOOL(false);
1367 PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
1371 tintervalle(PG_FUNCTION_ARGS)
1373 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1374 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1380 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1381 PG_RETURN_BOOL(false);
1388 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1389 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1390 PG_RETURN_BOOL(false);
1392 PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
1396 tintervalgt(PG_FUNCTION_ARGS)
1398 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1399 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1405 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1406 PG_RETURN_BOOL(false);
1413 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1414 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1415 PG_RETURN_BOOL(false);
1417 PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
1421 tintervalge(PG_FUNCTION_ARGS)
1423 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1424 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1430 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1431 PG_RETURN_BOOL(false);
1438 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1439 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1440 PG_RETURN_BOOL(false);
1442 PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
1447 * tintervalleneq - returns true iff length of interval i is equal to
1449 * tintervallenne - returns true iff length of interval i is not equal
1451 * tintervallenlt - returns true iff length of interval i is less than
1453 * tintervallengt - returns true iff length of interval i is greater
1455 * tintervallenle - returns true iff length of interval i is less or
1456 * equal than reltime t
1457 * tintervallenge - returns true iff length of interval i is greater or
1458 * equal than reltime t
1461 tintervalleneq(PG_FUNCTION_ARGS)
1463 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1464 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1467 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1468 PG_RETURN_BOOL(false);
1469 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1470 TimeIntervalGetDatum(i)));
1471 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
1475 tintervallenne(PG_FUNCTION_ARGS)
1477 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1478 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1481 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1482 PG_RETURN_BOOL(false);
1483 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1484 TimeIntervalGetDatum(i)));
1485 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
1489 tintervallenlt(PG_FUNCTION_ARGS)
1491 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1492 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1495 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1496 PG_RETURN_BOOL(false);
1497 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1498 TimeIntervalGetDatum(i)));
1499 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
1503 tintervallengt(PG_FUNCTION_ARGS)
1505 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1506 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1509 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1510 PG_RETURN_BOOL(false);
1511 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1512 TimeIntervalGetDatum(i)));
1513 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
1517 tintervallenle(PG_FUNCTION_ARGS)
1519 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1520 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1523 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1524 PG_RETURN_BOOL(false);
1525 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1526 TimeIntervalGetDatum(i)));
1527 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
1531 tintervallenge(PG_FUNCTION_ARGS)
1533 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1534 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1537 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1538 PG_RETURN_BOOL(false);
1539 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1540 TimeIntervalGetDatum(i)));
1541 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
1545 * tintervalct - returns true iff interval i1 contains interval i2
1548 tintervalct(PG_FUNCTION_ARGS)
1550 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1551 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1553 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1554 PG_RETURN_BOOL(false);
1555 if (DatumGetBool(DirectFunctionCall2(abstimele,
1556 AbsoluteTimeGetDatum(i1->data[0]),
1557 AbsoluteTimeGetDatum(i2->data[0]))) &&
1558 DatumGetBool(DirectFunctionCall2(abstimege,
1559 AbsoluteTimeGetDatum(i1->data[1]),
1560 AbsoluteTimeGetDatum(i2->data[1]))))
1561 PG_RETURN_BOOL(true);
1562 PG_RETURN_BOOL(false);
1566 * tintervalov - returns true iff interval i1 (partially) overlaps i2
1569 tintervalov(PG_FUNCTION_ARGS)
1571 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1572 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1574 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1575 PG_RETURN_BOOL(false);
1576 if (DatumGetBool(DirectFunctionCall2(abstimelt,
1577 AbsoluteTimeGetDatum(i1->data[1]),
1578 AbsoluteTimeGetDatum(i2->data[0]))) ||
1579 DatumGetBool(DirectFunctionCall2(abstimegt,
1580 AbsoluteTimeGetDatum(i1->data[0]),
1581 AbsoluteTimeGetDatum(i2->data[1]))))
1582 PG_RETURN_BOOL(false);
1583 PG_RETURN_BOOL(true);
1587 * tintervalstart - returns the start of interval i
1590 tintervalstart(PG_FUNCTION_ARGS)
1592 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1594 if (i->status == T_INTERVAL_INVAL)
1595 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1596 PG_RETURN_ABSOLUTETIME(i->data[0]);
1600 * tintervalend - returns the end of interval i
1603 tintervalend(PG_FUNCTION_ARGS)
1605 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1607 if (i->status == T_INTERVAL_INVAL)
1608 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1609 PG_RETURN_ABSOLUTETIME(i->data[1]);
1613 /*****************************************************************************
1614 * PRIVATE ROUTINES *
1615 *****************************************************************************/
1618 * istinterval - returns 1, iff i_string is a valid interval descr.
1619 * 0, iff i_string is NOT a valid interval desc.
1620 * 2, iff any time is INVALID_ABSTIME
1623 * i_start, i_end: interval margins
1626 * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1628 * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
1630 * where <AbsTime> satisfies the syntax of absolute time.
1632 * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
1635 istinterval(char *i_string,
1636 AbsoluteTime *i_start,
1637 AbsoluteTime *i_end)
1644 /* skip leading blanks up to '[' */
1645 while ((c = *p) != '\0')
1650 return 0; /* syntax error */
1655 /* skip leading blanks up to "'" */
1656 while ((c = *p) != '\0')
1661 return 0; /* syntax error */
1666 if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1667 return 0; /* undefined range, handled like a syntax
1669 /* search for the end of the first date and change it to a NULL */
1671 while ((c = *p1) != '\0')
1680 /* get the first date */
1681 *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1682 CStringGetDatum(p)));
1683 /* rechange NULL at the end of the first date to a "'" */
1686 /* skip blanks up to "'", beginning of second date */
1687 while ((c = *p) != '\0')
1692 return 0; /* syntax error */
1697 /* search for the end of the second date and change it to a NULL */
1699 while ((c = *p1) != '\0')
1708 /* get the second date */
1709 *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1710 CStringGetDatum(p)));
1711 /* rechange NULL at the end of the first date to a ''' */
1714 /* skip blanks up to ']' */
1715 while ((c = *p) != '\0')
1720 return 0; /* syntax error */
1727 return 0; /* syntax error */
1728 /* it seems to be a valid interval */
1733 /*****************************************************************************
1735 *****************************************************************************/
1739 * returns the current time as a text. similar to timenow() but returns
1740 * seconds with more precision (up to microsecs). (I need this to compare
1741 * the Wisconsin benchmark with Illustra whose TimeNow() shows current
1742 * time with precision up to microsecs.) - ay 3/95
1745 timeofday(PG_FUNCTION_ARGS)
1748 struct timezone tpz;
1754 gettimeofday(&tp, &tpz);
1755 strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1756 localtime((time_t *) &tp.tv_sec));
1757 snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1759 len = VARHDRSZ + strlen(buf);
1760 result = (text *) palloc(len);
1761 VARATT_SIZEP(result) = len;
1762 memcpy(VARDATA(result), buf, strlen(buf));
1763 PG_RETURN_TEXT_P(result);