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.108 2003/05/12 23:08:50 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)
242 elog(WARNING, "Invalid timezone \'%s\'",
249 #elif defined(HAVE_INT_TIMEZONE)
253 * We have a brute force time zone per SQL99? Then use it without
254 * change since we have already rotated to the time zone.
265 *tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
270 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
271 * case it contains an error message, which doesn't fit in
274 StrNCpy(*tzn, tzname[tm->tm_isdst], MAXTZLEN + 1);
275 if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)
276 elog(WARNING, "Invalid timezone \'%s\'",
277 tzname[tm->tm_isdst]);
283 #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
287 * We have a brute force time zone per SQL99? Then use it without
288 * change since we have already rotated to the time zone.
311 * Convert a tm structure to abstime.
312 * Note that tm has full year (not 1900-based) and 1-based month.
315 tm2abstime(struct tm * tm, int tz)
320 /* validate, before going out of range on some members */
321 if (tm->tm_year < 1901 || tm->tm_year > 2038
322 || tm->tm_mon < 1 || tm->tm_mon > 12
323 || tm->tm_mday < 1 || tm->tm_mday > 31
324 || tm->tm_hour < 0 || tm->tm_hour > 23
325 || tm->tm_min < 0 || tm->tm_min > 59
326 || tm->tm_sec < 0 || tm->tm_sec > 60)
327 return INVALID_ABSTIME;
329 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
331 /* check for time out of range */
332 if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
333 return INVALID_ABSTIME;
335 /* convert to seconds */
336 sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
338 /* check for overflow */
339 if ((day == MAX_DAYNUM && sec < 0) ||
340 (day == MIN_DAYNUM && sec > 0))
341 return INVALID_ABSTIME;
343 /* check for reserved values (e.g. "current" on edge of usual range */
344 if (!AbsoluteTimeIsReal(sec))
345 return INVALID_ABSTIME;
352 * Decode date/time string and return abstime.
355 abstimein(PG_FUNCTION_ARGS)
357 char *str = PG_GETARG_CSTRING(0);
363 char *field[MAXDATEFIELDS];
364 char lowstr[MAXDATELEN + 1];
367 ftype[MAXDATEFIELDS];
369 if (strlen(str) >= sizeof(lowstr))
370 elog(ERROR, "Bad abstime external representation (too long) '%s'", str);
372 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
373 || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
374 elog(ERROR, "Bad abstime external representation '%s'", str);
379 result = tm2abstime(tm, tz);
385 * Don't bother retaining this as a reserved value, but
386 * instead just set to the actual epoch time (1970-01-01)
392 result = NOEND_ABSTIME;
396 result = NOSTART_ABSTIME;
400 result = INVALID_ABSTIME;
404 elog(ERROR, "Bad abstime (internal coding error) '%s'", str);
405 result = INVALID_ABSTIME;
409 PG_RETURN_ABSOLUTETIME(result);
414 * Given an AbsoluteTime return the English text version of the date
417 abstimeout(PG_FUNCTION_ARGS)
419 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
425 char buf[MAXDATELEN + 1];
426 char zone[MAXDATELEN + 1],
432 * Note that timestamp no longer supports 'invalid'. Retain
433 * 'invalid' for abstime for now, but dump it someday.
435 case INVALID_ABSTIME:
436 strcpy(buf, INVALID);
441 case NOSTART_ABSTIME:
445 abstime2tm(time, &tz, tm, &tzn);
446 EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
450 result = pstrdup(buf);
451 PG_RETURN_CSTRING(result);
455 * abstimerecv - converts external binary format to abstime
458 abstimerecv(PG_FUNCTION_ARGS)
460 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
462 PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
466 * abstimesend - converts abstime to binary format
469 abstimesend(PG_FUNCTION_ARGS)
471 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
474 pq_begintypsend(&buf);
475 pq_sendint(&buf, time, sizeof(time));
476 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
483 abstime_finite(PG_FUNCTION_ARGS)
485 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
487 PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&
488 (abstime != NOSTART_ABSTIME) &&
489 (abstime != NOEND_ABSTIME));
494 * abstime comparison routines
497 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
500 * We consider all INVALIDs to be equal and larger than any non-INVALID.
501 * This is somewhat arbitrary; the important thing is to have a
502 * consistent sort order.
504 if (a == INVALID_ABSTIME)
506 if (b == INVALID_ABSTIME)
507 return 0; /* INVALID = INVALID */
509 return 1; /* INVALID > non-INVALID */
512 if (b == INVALID_ABSTIME)
513 return -1; /* non-INVALID < INVALID */
516 /* CURRENT is no longer stored internally... */
517 /* XXX this is broken, should go away: */
518 if (a == CURRENT_ABSTIME)
519 a = GetCurrentTransactionStartTime();
520 if (b == CURRENT_ABSTIME)
521 b = GetCurrentTransactionStartTime();
533 abstimeeq(PG_FUNCTION_ARGS)
535 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
536 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
538 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
542 abstimene(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 abstimelt(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 abstimegt(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 abstimele(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 abstimege(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 btabstimecmp(PG_FUNCTION_ARGS)
589 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
590 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
592 PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
596 /* timestamp_abstime()
597 * Convert timestamp to abstime.
600 timestamp_abstime(PG_FUNCTION_ARGS)
602 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
609 if (TIMESTAMP_IS_NOBEGIN(timestamp))
610 result = NOSTART_ABSTIME;
611 else if (TIMESTAMP_IS_NOEND(timestamp))
612 result = NOEND_ABSTIME;
613 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
615 tz = DetermineLocalTimeZone(tm);
616 result = tm2abstime(tm, tz);
620 elog(ERROR, "Unable to convert timestamp to abstime");
621 result = INVALID_ABSTIME;
624 PG_RETURN_ABSOLUTETIME(result);
627 /* abstime_timestamp()
628 * Convert abstime to timestamp.
631 abstime_timestamp(PG_FUNCTION_ARGS)
633 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
638 char zone[MAXDATELEN + 1],
643 case INVALID_ABSTIME:
644 elog(ERROR, "Unable to convert abstime 'invalid' to timestamp");
645 TIMESTAMP_NOBEGIN(result);
648 case NOSTART_ABSTIME:
649 TIMESTAMP_NOBEGIN(result);
653 TIMESTAMP_NOEND(result);
657 abstime2tm(abstime, &tz, tm, &tzn);
658 if (tm2timestamp(tm, 0, NULL, &result) != 0)
659 elog(ERROR, "Unable to convert ABSTIME to TIMESTAMP"
660 "\n\tabstime_timestamp() internal error");
664 PG_RETURN_TIMESTAMP(result);
668 /* timestamptz_abstime()
669 * Convert timestamp with time zone to abstime.
672 timestamptz_abstime(PG_FUNCTION_ARGS)
674 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
680 if (TIMESTAMP_IS_NOBEGIN(timestamp))
681 result = NOSTART_ABSTIME;
682 else if (TIMESTAMP_IS_NOEND(timestamp))
683 result = NOEND_ABSTIME;
684 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
685 result = tm2abstime(tm, 0);
688 elog(ERROR, "Unable to convert timestamp to abstime");
689 result = INVALID_ABSTIME;
692 PG_RETURN_ABSOLUTETIME(result);
695 /* abstime_timestamptz()
696 * Convert abstime to timestamp with time zone.
699 abstime_timestamptz(PG_FUNCTION_ARGS)
701 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
706 char zone[MAXDATELEN + 1],
711 case INVALID_ABSTIME:
712 elog(ERROR, "Unable to convert abstime 'invalid' to timestamptz");
713 TIMESTAMP_NOBEGIN(result);
716 case NOSTART_ABSTIME:
717 TIMESTAMP_NOBEGIN(result);
721 TIMESTAMP_NOEND(result);
725 abstime2tm(abstime, &tz, tm, &tzn);
726 if (tm2timestamp(tm, 0, &tz, &result) != 0)
727 elog(ERROR, "Unable to convert ABSTIME to TIMESTAMP WITH TIME ZONE"
728 "\n\tabstime_timestamptz() internal error");
732 PG_RETURN_TIMESTAMP(result);
736 /*****************************************************************************
737 * USER I/O ROUTINES *
738 *****************************************************************************/
741 * reltimein - converts a reltime string in an internal format
744 reltimein(PG_FUNCTION_ARGS)
746 char *str = PG_GETARG_CSTRING(0);
752 char *field[MAXDATEFIELDS];
754 ftype[MAXDATEFIELDS];
755 char lowstr[MAXDATELEN + 1];
757 if (strlen(str) >= sizeof(lowstr))
758 elog(ERROR, "Bad reltime external representation (too long) '%s'", str);
760 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
761 || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
762 elog(ERROR, "Bad reltime external representation '%s'", str);
767 result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
768 result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
772 elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
773 result = INVALID_RELTIME;
777 PG_RETURN_RELATIVETIME(result);
781 * reltimeout - converts the internal format to a reltime string
784 reltimeout(PG_FUNCTION_ARGS)
786 RelativeTime time = PG_GETARG_RELATIVETIME(0);
790 char buf[MAXDATELEN + 1];
792 reltime2tm(time, tm);
793 EncodeInterval(tm, 0, DateStyle, buf);
795 result = pstrdup(buf);
796 PG_RETURN_CSTRING(result);
800 * reltimerecv - converts external binary format to reltime
803 reltimerecv(PG_FUNCTION_ARGS)
805 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
807 PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
811 * reltimesend - converts reltime to binary format
814 reltimesend(PG_FUNCTION_ARGS)
816 RelativeTime time = PG_GETARG_RELATIVETIME(0);
819 pq_begintypsend(&buf);
820 pq_sendint(&buf, time, sizeof(time));
821 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
826 reltime2tm(RelativeTime time, struct tm * tm)
828 TMODULO(time, tm->tm_year, 31557600);
829 TMODULO(time, tm->tm_mon, 2592000);
830 TMODULO(time, tm->tm_mday, 86400);
831 TMODULO(time, tm->tm_hour, 3600);
832 TMODULO(time, tm->tm_min, 60);
833 TMODULO(time, tm->tm_sec, 1);
838 * tintervalin - converts an interval string to internal format
841 tintervalin(PG_FUNCTION_ARGS)
843 char *intervalstr = PG_GETARG_CSTRING(0);
844 TimeInterval interval;
845 AbsoluteTime i_start,
850 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
851 if (istinterval(intervalstr, &t1, &t2) == 0)
852 elog(ERROR, "Unable to decode tinterval '%s'", intervalstr);
854 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
855 interval->status = T_INTERVAL_INVAL; /* undefined */
857 interval->status = T_INTERVAL_VALID;
859 i_start = ABSTIMEMIN(t1, t2);
860 i_end = ABSTIMEMAX(t1, t2);
861 interval->data[0] = i_start;
862 interval->data[1] = i_end;
864 PG_RETURN_TIMEINTERVAL(interval);
869 * tintervalout - converts an internal interval format to a string
872 tintervalout(PG_FUNCTION_ARGS)
874 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
878 i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
879 strcpy(i_str, "[\"");
880 if (interval->status == T_INTERVAL_INVAL)
881 strcat(i_str, INVALID_INTERVAL_STR);
884 p = DatumGetCString(DirectFunctionCall1(abstimeout,
885 AbsoluteTimeGetDatum(interval->data[0])));
888 strcat(i_str, "\" \"");
889 p = DatumGetCString(DirectFunctionCall1(abstimeout,
890 AbsoluteTimeGetDatum(interval->data[1])));
894 strcat(i_str, "\"]\0");
895 PG_RETURN_CSTRING(i_str);
899 * tintervalrecv - converts external binary format to tinterval
902 tintervalrecv(PG_FUNCTION_ARGS)
904 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
905 TimeInterval interval;
907 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
909 interval->status = pq_getmsgint(buf, sizeof(interval->status));
910 if (!(interval->status == T_INTERVAL_INVAL ||
911 interval->status == T_INTERVAL_VALID))
912 elog(ERROR, "Invalid status in external tinterval");
913 interval->data[0] = pq_getmsgint(buf, sizeof(interval->data[0]));
914 interval->data[1] = pq_getmsgint(buf, sizeof(interval->data[1]));
916 PG_RETURN_TIMEINTERVAL(interval);
920 * tintervalsend - converts tinterval to binary format
923 tintervalsend(PG_FUNCTION_ARGS)
925 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
928 pq_begintypsend(&buf);
929 pq_sendint(&buf, interval->status, sizeof(interval->status));
930 pq_sendint(&buf, interval->data[0], sizeof(interval->data[0]));
931 pq_sendint(&buf, interval->data[1], sizeof(interval->data[1]));
932 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
936 /*****************************************************************************
938 *****************************************************************************/
941 interval_reltime(PG_FUNCTION_ARGS)
943 Interval *interval = PG_GETARG_INTERVAL_P(0);
948 #ifdef HAVE_INT64_TIMESTAMP
955 if (interval->month == 0)
960 else if (abs(interval->month) >= 12)
962 year = (interval->month / 12);
963 month = (interval->month % 12);
968 month = interval->month;
971 #ifdef HAVE_INT64_TIMESTAMP
972 span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
973 * INT64CONST(86400)) + interval->time);
974 span /= INT64CONST(1000000);
976 span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
979 if ((span < INT_MIN) || (span > INT_MAX))
980 time = INVALID_RELTIME;
984 PG_RETURN_RELATIVETIME(time);
989 reltime_interval(PG_FUNCTION_ARGS)
991 RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
996 result = (Interval *) palloc(sizeof(Interval));
1000 case INVALID_RELTIME:
1001 elog(ERROR, "Unable to convert reltime 'invalid' to interval");
1007 #ifdef HAVE_INT64_TIMESTAMP
1008 year = (reltime / (36525 * 864));
1009 reltime -= (year * (36525 * 864));
1010 month = (reltime / (30 * 86400));
1011 reltime -= (month * (30 * 86400));
1013 result->time = (reltime * INT64CONST(1000000));
1015 TMODULO(reltime, year, (36525 * 864));
1016 TMODULO(reltime, month, (30 * 86400));
1018 result->time = reltime;
1020 result->month = ((12 * year) + month);
1024 PG_RETURN_INTERVAL_P(result);
1029 * mktinterval - creates a time interval with endpoints t1 and t2
1032 mktinterval(PG_FUNCTION_ARGS)
1034 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1035 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
1036 AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
1037 AbsoluteTime tend = ABSTIMEMAX(t1, t2);
1038 TimeInterval interval;
1040 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
1042 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1043 interval->status = T_INTERVAL_INVAL;
1046 interval->status = T_INTERVAL_VALID;
1047 interval->data[0] = tstart;
1048 interval->data[1] = tend;
1051 PG_RETURN_TIMEINTERVAL(interval);
1055 * timepl, timemi and abstimemi use the formula
1056 * abstime + reltime = abstime
1057 * so abstime - reltime = abstime
1058 * and abstime - abstime = reltime
1062 * timepl - returns the value of (abstime t1 + reltime t2)
1065 timepl(PG_FUNCTION_ARGS)
1067 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1068 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1070 if (AbsoluteTimeIsReal(t1) &&
1071 RelativeTimeIsValid(t2) &&
1072 ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
1073 : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
1074 PG_RETURN_ABSOLUTETIME(t1 + t2);
1076 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1081 * timemi - returns the value of (abstime t1 - reltime t2)
1084 timemi(PG_FUNCTION_ARGS)
1086 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1087 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1089 if (AbsoluteTimeIsReal(t1) &&
1090 RelativeTimeIsValid(t2) &&
1091 ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
1092 : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
1093 PG_RETURN_ABSOLUTETIME(t1 - t2);
1095 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1100 * intinterval - returns true iff absolute date is in the interval
1103 intinterval(PG_FUNCTION_ARGS)
1105 AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
1106 TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
1108 if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1110 if (DatumGetBool(DirectFunctionCall2(abstimege,
1111 AbsoluteTimeGetDatum(t),
1112 AbsoluteTimeGetDatum(interval->data[0]))) &&
1113 DatumGetBool(DirectFunctionCall2(abstimele,
1114 AbsoluteTimeGetDatum(t),
1115 AbsoluteTimeGetDatum(interval->data[1]))))
1116 PG_RETURN_BOOL(true);
1118 PG_RETURN_BOOL(false);
1122 * tintervalrel - returns relative time corresponding to interval
1125 tintervalrel(PG_FUNCTION_ARGS)
1127 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1128 AbsoluteTime t1 = interval->data[0];
1129 AbsoluteTime t2 = interval->data[1];
1131 if (interval->status != T_INTERVAL_VALID)
1132 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1134 if (AbsoluteTimeIsReal(t1) &&
1135 AbsoluteTimeIsReal(t2))
1136 PG_RETURN_RELATIVETIME(t2 - t1);
1138 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1143 * timenow - returns time "now", internal format
1145 * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1148 timenow(PG_FUNCTION_ARGS)
1153 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1155 PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1159 * reltimeeq - returns true iff arguments are equal
1160 * reltimene - returns true iff arguments are not equal
1161 * reltimelt - returns true iff t1 less than t2
1162 * reltimegt - returns true iff t1 greater than t2
1163 * reltimele - returns true iff t1 less than or equal to t2
1164 * reltimege - returns true iff t1 greater than or equal to t2
1167 reltimeeq(PG_FUNCTION_ARGS)
1169 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1170 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1172 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1173 PG_RETURN_BOOL(false);
1174 PG_RETURN_BOOL(t1 == t2);
1178 reltimene(PG_FUNCTION_ARGS)
1180 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1181 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1183 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1184 PG_RETURN_BOOL(false);
1185 PG_RETURN_BOOL(t1 != t2);
1189 reltimelt(PG_FUNCTION_ARGS)
1191 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1192 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1194 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1195 PG_RETURN_BOOL(false);
1196 PG_RETURN_BOOL(t1 < t2);
1200 reltimegt(PG_FUNCTION_ARGS)
1202 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1203 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1205 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1206 PG_RETURN_BOOL(false);
1207 PG_RETURN_BOOL(t1 > t2);
1211 reltimele(PG_FUNCTION_ARGS)
1213 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1214 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1216 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1217 PG_RETURN_BOOL(false);
1218 PG_RETURN_BOOL(t1 <= t2);
1222 reltimege(PG_FUNCTION_ARGS)
1224 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1225 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1227 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1228 PG_RETURN_BOOL(false);
1229 PG_RETURN_BOOL(t1 >= t2);
1234 * tintervalsame - returns true iff interval i1 is same as interval i2
1235 * Check begin and end time.
1238 tintervalsame(PG_FUNCTION_ARGS)
1240 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1241 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1243 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1244 PG_RETURN_BOOL(false);
1246 if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1247 AbsoluteTimeGetDatum(i1->data[0]),
1248 AbsoluteTimeGetDatum(i2->data[0]))) &&
1249 DatumGetBool(DirectFunctionCall2(abstimeeq,
1250 AbsoluteTimeGetDatum(i1->data[1]),
1251 AbsoluteTimeGetDatum(i2->data[1]))))
1252 PG_RETURN_BOOL(true);
1253 PG_RETURN_BOOL(false);
1258 * tintervaleq - returns true iff interval i1 is equal to interval i2
1259 * Check length of intervals.
1262 tintervaleq(PG_FUNCTION_ARGS)
1264 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1265 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1271 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1272 PG_RETURN_BOOL(false);
1279 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1280 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1281 PG_RETURN_BOOL(false);
1283 PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
1287 tintervalne(PG_FUNCTION_ARGS)
1289 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1290 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1296 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1297 PG_RETURN_BOOL(false);
1304 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1305 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1306 PG_RETURN_BOOL(false);
1308 PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
1312 tintervallt(PG_FUNCTION_ARGS)
1314 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1315 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1321 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1322 PG_RETURN_BOOL(false);
1329 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1330 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1331 PG_RETURN_BOOL(false);
1333 PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
1337 tintervalle(PG_FUNCTION_ARGS)
1339 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1340 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1346 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1347 PG_RETURN_BOOL(false);
1354 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1355 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1356 PG_RETURN_BOOL(false);
1358 PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
1362 tintervalgt(PG_FUNCTION_ARGS)
1364 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1365 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1371 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1372 PG_RETURN_BOOL(false);
1379 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1380 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1381 PG_RETURN_BOOL(false);
1383 PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
1387 tintervalge(PG_FUNCTION_ARGS)
1389 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1390 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1396 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1397 PG_RETURN_BOOL(false);
1404 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1405 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1406 PG_RETURN_BOOL(false);
1408 PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
1413 * tintervalleneq - returns true iff length of interval i is equal to
1415 * tintervallenne - returns true iff length of interval i is not equal
1417 * tintervallenlt - returns true iff length of interval i is less than
1419 * tintervallengt - returns true iff length of interval i is greater
1421 * tintervallenle - returns true iff length of interval i is less or
1422 * equal than reltime t
1423 * tintervallenge - returns true iff length of interval i is greater or
1424 * equal than reltime t
1427 tintervalleneq(PG_FUNCTION_ARGS)
1429 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1430 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1433 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1434 PG_RETURN_BOOL(false);
1435 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1436 TimeIntervalGetDatum(i)));
1437 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
1441 tintervallenne(PG_FUNCTION_ARGS)
1443 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1444 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1447 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1448 PG_RETURN_BOOL(false);
1449 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1450 TimeIntervalGetDatum(i)));
1451 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
1455 tintervallenlt(PG_FUNCTION_ARGS)
1457 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1458 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1461 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1462 PG_RETURN_BOOL(false);
1463 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1464 TimeIntervalGetDatum(i)));
1465 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
1469 tintervallengt(PG_FUNCTION_ARGS)
1471 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1472 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1475 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1476 PG_RETURN_BOOL(false);
1477 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1478 TimeIntervalGetDatum(i)));
1479 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
1483 tintervallenle(PG_FUNCTION_ARGS)
1485 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1486 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1489 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1490 PG_RETURN_BOOL(false);
1491 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1492 TimeIntervalGetDatum(i)));
1493 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
1497 tintervallenge(PG_FUNCTION_ARGS)
1499 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1500 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1503 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1504 PG_RETURN_BOOL(false);
1505 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1506 TimeIntervalGetDatum(i)));
1507 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
1511 * tintervalct - returns true iff interval i1 contains interval i2
1514 tintervalct(PG_FUNCTION_ARGS)
1516 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1517 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1519 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1520 PG_RETURN_BOOL(false);
1521 if (DatumGetBool(DirectFunctionCall2(abstimele,
1522 AbsoluteTimeGetDatum(i1->data[0]),
1523 AbsoluteTimeGetDatum(i2->data[0]))) &&
1524 DatumGetBool(DirectFunctionCall2(abstimege,
1525 AbsoluteTimeGetDatum(i1->data[1]),
1526 AbsoluteTimeGetDatum(i2->data[1]))))
1527 PG_RETURN_BOOL(true);
1528 PG_RETURN_BOOL(false);
1532 * tintervalov - returns true iff interval i1 (partially) overlaps i2
1535 tintervalov(PG_FUNCTION_ARGS)
1537 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1538 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1540 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1541 PG_RETURN_BOOL(false);
1542 if (DatumGetBool(DirectFunctionCall2(abstimelt,
1543 AbsoluteTimeGetDatum(i1->data[1]),
1544 AbsoluteTimeGetDatum(i2->data[0]))) ||
1545 DatumGetBool(DirectFunctionCall2(abstimegt,
1546 AbsoluteTimeGetDatum(i1->data[0]),
1547 AbsoluteTimeGetDatum(i2->data[1]))))
1548 PG_RETURN_BOOL(false);
1549 PG_RETURN_BOOL(true);
1553 * tintervalstart - returns the start of interval i
1556 tintervalstart(PG_FUNCTION_ARGS)
1558 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1560 if (i->status == T_INTERVAL_INVAL)
1561 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1562 PG_RETURN_ABSOLUTETIME(i->data[0]);
1566 * tintervalend - returns the end of interval i
1569 tintervalend(PG_FUNCTION_ARGS)
1571 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1573 if (i->status == T_INTERVAL_INVAL)
1574 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1575 PG_RETURN_ABSOLUTETIME(i->data[1]);
1579 /*****************************************************************************
1580 * PRIVATE ROUTINES *
1581 *****************************************************************************/
1584 * istinterval - returns 1, iff i_string is a valid interval descr.
1585 * 0, iff i_string is NOT a valid interval desc.
1586 * 2, iff any time is INVALID_ABSTIME
1589 * i_start, i_end: interval margins
1592 * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1594 * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
1596 * where <AbsTime> satisfies the syntax of absolute time.
1598 * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
1601 istinterval(char *i_string,
1602 AbsoluteTime *i_start,
1603 AbsoluteTime *i_end)
1610 /* skip leading blanks up to '[' */
1611 while ((c = *p) != '\0')
1616 return 0; /* syntax error */
1621 /* skip leading blanks up to "'" */
1622 while ((c = *p) != '\0')
1627 return 0; /* syntax error */
1632 if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1633 return 0; /* undefined range, handled like a syntax
1635 /* search for the end of the first date and change it to a NULL */
1637 while ((c = *p1) != '\0')
1646 /* get the first date */
1647 *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1648 CStringGetDatum(p)));
1649 /* rechange NULL at the end of the first date to a "'" */
1652 /* skip blanks up to "'", beginning of second date */
1653 while ((c = *p) != '\0')
1658 return 0; /* syntax error */
1663 /* search for the end of the second date and change it to a NULL */
1665 while ((c = *p1) != '\0')
1674 /* get the second date */
1675 *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1676 CStringGetDatum(p)));
1677 /* rechange NULL at the end of the first date to a ''' */
1680 /* skip blanks up to ']' */
1681 while ((c = *p) != '\0')
1686 return 0; /* syntax error */
1693 return 0; /* syntax error */
1694 /* it seems to be a valid interval */
1699 /*****************************************************************************
1701 *****************************************************************************/
1705 * returns the current time as a text. similar to timenow() but returns
1706 * seconds with more precision (up to microsecs). (I need this to compare
1707 * the Wisconsin benchmark with Illustra whose TimeNow() shows current
1708 * time with precision up to microsecs.) - ay 3/95
1711 timeofday(PG_FUNCTION_ARGS)
1714 struct timezone tpz;
1720 gettimeofday(&tp, &tpz);
1721 strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1722 localtime((time_t *) &tp.tv_sec));
1723 snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1725 len = VARHDRSZ + strlen(buf);
1726 result = (text *) palloc(len);
1727 VARATT_SIZEP(result) = len;
1728 memcpy(VARDATA(result), buf, strlen(buf));
1729 PG_RETURN_TEXT_P(result);