1 /*-------------------------------------------------------------------------
3 * Utilities for the built-in type "AbsoluteTime".
4 * Functions for the built-in type "RelativeTime".
5 * Functions for the built-in type "TimeInterval".
7 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.94 2002/06/11 13:40:52 wieck Exp $
16 *-------------------------------------------------------------------------
23 #include <sys/types.h>
27 #if !(defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE))
28 #include <sys/timeb.h>
31 #include "access/xact.h"
32 #include "miscadmin.h"
33 #include "utils/builtins.h"
36 #define MIN_DAYNUM -24856 /* December 13, 1901 */
37 #define MAX_DAYNUM 24854 /* January 18, 2038 */
39 #define INVALID_RELTIME_STR "Undefined RelTime"
40 #define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
41 #define RELTIME_LABEL '@'
42 #define RELTIME_PAST "ago"
43 #define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
46 * Unix epoch is Jan 1 00:00:00 1970.
47 * Postgres knows about times sixty-eight years on either side of that
48 * for these 4-byte types.
50 * "tinterval" is two 4-byte fields.
51 * Definitions for parsing tinterval.
54 #define IsSpace(C) ((C) == ' ')
56 #define T_INTERVAL_INVAL 0 /* data represents no valid interval */
57 #define T_INTERVAL_VALID 1 /* data represents a valid interval */
59 * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
61 * 1234567890123456789012345678901234567890123456789012345678901234
63 * we allocate some extra -- timezones are usually 3 characters but
64 * this is not in the POSIX standard...
66 #define T_INTERVAL_LEN 80
67 #define INVALID_INTERVAL_STR "Undefined Range"
68 #define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
70 #define ABSTIMEMIN(t1, t2) \
71 (DatumGetBool(DirectFunctionCall2(abstimele, \
72 AbsoluteTimeGetDatum(t1), \
73 AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
74 #define ABSTIMEMAX(t1, t2) \
75 (DatumGetBool(DirectFunctionCall2(abstimelt, \
76 AbsoluteTimeGetDatum(t1), \
77 AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
81 * Function prototypes -- internal to this file only
84 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
85 static void reltime2tm(RelativeTime time, struct tm * tm);
86 static int istinterval(char *i_string,
87 AbsoluteTime *i_start,
91 /* GetCurrentAbsoluteTime()
92 * Get the current system time. Set timezone parameters if not specified elsewhere.
93 * Define HasCTZSet to allow clients to specify the default timezone.
95 * Returns the number of seconds since epoch (January 1 1970 GMT)
98 GetCurrentAbsoluteTime(void)
102 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
107 struct timeb tb; /* the old V7-ism */
115 #if defined(HAVE_TM_ZONE)
116 tm = localtime(&now);
118 CTimeZone = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
119 CDayLight = (tm->tm_isdst > 0);
124 * XXX is there a better way to get local timezone string w/o
125 * tzname? - tgl 97/03/18
127 strftime(CTZName, MAXTZLEN, "%Z", tm);
131 * XXX FreeBSD man pages indicate that this should work - thomas
134 strcpy(CTZName, tm->tm_zone);
136 #elif defined(HAVE_INT_TIMEZONE)
137 tm = localtime(&now);
139 CDayLight = tm->tm_isdst;
140 CTimeZone = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
141 strcpy(CTZName, tzname[tm->tm_isdst]);
142 #else /* neither HAVE_TM_ZONE nor
143 * HAVE_INT_TIMEZONE */
144 CTimeZone = tb.timezone * 60;
145 CDayLight = (tb.dstflag != 0);
148 * XXX does this work to get the local timezone string in V7? -
151 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
155 return (AbsoluteTime) now;
156 } /* GetCurrentAbsoluteTime() */
159 /* GetCurrentAbsoluteTimeUsec()
160 * Get the current system time. Set timezone parameters if not specified elsewhere.
161 * Define HasCTZSet to allow clients to specify the default timezone.
163 * Returns the number of seconds since epoch (January 1 1970 GMT)
166 GetCurrentAbsoluteTimeUsec(int *usec)
174 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
178 struct timeb tb; /* the old V7-ism */
181 gettimeofday(&tp, NULL);
187 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
197 #if defined(HAVE_TM_ZONE)
198 tm = localtime(&now);
200 CTimeZone = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
201 CDayLight = (tm->tm_isdst > 0);
206 * XXX is there a better way to get local timezone string w/o
207 * tzname? - tgl 97/03/18
209 strftime(CTZName, MAXTZLEN, "%Z", tm);
213 * XXX FreeBSD man pages indicate that this should work - thomas
216 strcpy(CTZName, tm->tm_zone);
218 #elif defined(HAVE_INT_TIMEZONE)
219 tm = localtime(&now);
221 CDayLight = tm->tm_isdst;
222 CTimeZone = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
223 strcpy(CTZName, tzname[tm->tm_isdst]);
224 #else /* neither HAVE_TM_ZONE nor
225 * HAVE_INT_TIMEZONE */
226 CTimeZone = tb.timezone * 60;
227 CDayLight = (tb.dstflag != 0);
230 * XXX does this work to get the local timezone string in V7? -
233 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
237 return (AbsoluteTime) now;
238 } /* GetCurrentAbsoluteTimeUsec() */
242 GetCurrentDateTime(struct tm * tm)
246 abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
249 } /* GetCurrentDateTime() */
253 GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec)
258 abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
259 #ifdef HAVE_INT64_TIMESTAMP
262 *fsec = usec * 1.0e-6;
266 } /* GetCurrentTimeUsec() */
270 abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn)
272 time_t time = (time_t) _time;
274 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
278 struct timeb tb; /* the old V7-ism */
284 * If HasCTZSet is true then we have a brute force time zone
285 * specified. Go ahead and rotate to the local time zone since we will
286 * later bypass any calls which adjust the tm fields.
288 if (HasCTZSet && (tzp != NULL))
291 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
292 if ((!HasCTZSet) && (tzp != NULL))
294 tx = localtime((time_t *) &time);
295 #ifdef NO_MKTIME_BEFORE_1970
296 if (tx->tm_year < 70 && tx->tm_isdst == 1)
299 tx = localtime((time_t *) &time);
306 tx = gmtime((time_t *) &time);
309 tm->tm_year = tx->tm_year + 1900;
310 tm->tm_mon = tx->tm_mon + 1;
311 tm->tm_mday = tx->tm_mday;
312 tm->tm_hour = tx->tm_hour;
313 tm->tm_min = tx->tm_min;
314 tm->tm_sec = tx->tm_sec;
315 tm->tm_isdst = tx->tm_isdst;
317 #if defined(HAVE_TM_ZONE)
318 tm->tm_gmtoff = tx->tm_gmtoff;
319 tm->tm_zone = tx->tm_zone;
324 * We have a brute force time zone per SQL99? Then use it without
325 * change since we have already rotated to the time zone.
330 tm->tm_gmtoff = CTimeZone;
338 *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
341 * XXX FreeBSD man pages indicate that this should work - tgl
347 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
348 * case it contains an error message, which doesn't fit in
351 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
352 if (strlen(tm->tm_zone) > MAXTZLEN)
353 elog(WARNING, "Invalid timezone \'%s\'", tm->tm_zone);
359 #elif defined(HAVE_INT_TIMEZONE)
363 * We have a brute force time zone per SQL99? Then use it without
364 * change since we have already rotated to the time zone.
375 *tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
380 * Copy no more than MAXTZLEN bytes of timezone to tzn, in
381 * case it contains an error message, which doesn't fit in
384 StrNCpy(*tzn, tzname[tm->tm_isdst], MAXTZLEN + 1);
385 if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)
386 elog(WARNING, "Invalid timezone \'%s\'", tzname[tm->tm_isdst]);
393 #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
397 * We have a brute force time zone per SQL99? Then use it without
398 * change since we have already rotated to the time zone.
408 *tzp = tb.timezone * 60;
411 * XXX does this work to get the local timezone string in V7?
416 strftime(*tzn, MAXTZLEN, "%Z", localtime(&now));
417 tzn[MAXTZLEN] = '\0'; /* let's just be sure it's
431 * Convert a tm structure to abstime.
432 * Note that tm has full year (not 1900-based) and 1-based month.
435 tm2abstime(struct tm * tm, int tz)
440 /* validate, before going out of range on some members */
441 if (tm->tm_year < 1901 || tm->tm_year > 2038
442 || tm->tm_mon < 1 || tm->tm_mon > 12
443 || tm->tm_mday < 1 || tm->tm_mday > 31
444 || tm->tm_hour < 0 || tm->tm_hour >= 24
445 || tm->tm_min < 0 || tm->tm_min > 59
446 || tm->tm_sec < 0 || tm->tm_sec > 59)
447 return INVALID_ABSTIME;
449 day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
451 /* check for time out of range */
452 if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
453 return INVALID_ABSTIME;
455 /* convert to seconds */
456 sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
458 /* check for overflow */
459 if ((day == MAX_DAYNUM && sec < 0) ||
460 (day == MIN_DAYNUM && sec > 0))
461 return INVALID_ABSTIME;
463 /* check for reserved values (e.g. "current" on edge of usual range */
464 if (!AbsoluteTimeIsReal(sec))
465 return INVALID_ABSTIME;
472 * Decode date/time string and return abstime.
475 nabstimein(PG_FUNCTION_ARGS)
477 char *str = PG_GETARG_CSTRING(0);
483 char *field[MAXDATEFIELDS];
484 char lowstr[MAXDATELEN + 1];
487 ftype[MAXDATEFIELDS];
489 if (strlen(str) > MAXDATELEN)
490 elog(ERROR, "Bad (length) abstime external representation '%s'", str);
492 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
493 || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
494 elog(ERROR, "Bad abstime external representation '%s'", str);
499 result = tm2abstime(tm, tz);
505 * Don't bother retaining this as a reserved value, but
506 * instead just set to the actual epoch time (1970-01-01)
512 result = NOEND_ABSTIME;
516 result = NOSTART_ABSTIME;
520 result = INVALID_ABSTIME;
524 elog(ERROR, "Bad abstime (internal coding error) '%s'", str);
525 result = INVALID_ABSTIME;
529 PG_RETURN_ABSOLUTETIME(result);
534 * Given an AbsoluteTime return the English text version of the date
537 nabstimeout(PG_FUNCTION_ARGS)
539 AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
545 char buf[MAXDATELEN + 1];
546 char zone[MAXDATELEN + 1],
552 * Note that timestamp no longer supports 'invalid'. Retain
553 * 'invalid' for abstime for now, but dump it someday.
555 case INVALID_ABSTIME:
556 strcpy(buf, INVALID);
561 case NOSTART_ABSTIME:
565 abstime2tm(time, &tz, tm, &tzn);
566 EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
570 result = pstrdup(buf);
571 PG_RETURN_CSTRING(result);
578 abstime_finite(PG_FUNCTION_ARGS)
580 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
582 PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&
583 (abstime != NOSTART_ABSTIME) &&
584 (abstime != NOEND_ABSTIME));
589 * abstime comparison routines
592 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
595 * We consider all INVALIDs to be equal and larger than any non-INVALID.
596 * This is somewhat arbitrary; the important thing is to have a
597 * consistent sort order.
599 if (a == INVALID_ABSTIME)
601 if (b == INVALID_ABSTIME)
602 return 0; /* INVALID = INVALID */
604 return 1; /* INVALID > non-INVALID */
607 if (b == INVALID_ABSTIME)
608 return -1; /* non-INVALID < INVALID */
611 /* CURRENT is no longer stored internally... */
612 /* XXX this is broken, should go away: */
613 if (a == CURRENT_ABSTIME)
614 a = GetCurrentTransactionStartTime();
615 if (b == CURRENT_ABSTIME)
616 b = GetCurrentTransactionStartTime();
628 abstimeeq(PG_FUNCTION_ARGS)
630 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
631 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
633 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
637 abstimene(PG_FUNCTION_ARGS)
639 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
640 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
642 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
646 abstimelt(PG_FUNCTION_ARGS)
648 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
649 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
651 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
655 abstimegt(PG_FUNCTION_ARGS)
657 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
658 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
660 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
664 abstimele(PG_FUNCTION_ARGS)
666 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
667 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
669 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
673 abstimege(PG_FUNCTION_ARGS)
675 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
676 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
678 PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
682 btabstimecmp(PG_FUNCTION_ARGS)
684 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
685 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
687 PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
691 /* timestamp_abstime()
692 * Convert timestamp to abstime.
695 timestamp_abstime(PG_FUNCTION_ARGS)
697 Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
704 if (TIMESTAMP_IS_NOBEGIN(timestamp))
705 result = NOSTART_ABSTIME;
706 else if (TIMESTAMP_IS_NOEND(timestamp))
707 result = NOEND_ABSTIME;
708 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
710 tz = DetermineLocalTimeZone(tm);
711 result = tm2abstime(tm, tz);
715 elog(ERROR, "Unable to convert timestamp to abstime");
716 result = INVALID_ABSTIME;
719 PG_RETURN_ABSOLUTETIME(result);
722 /* abstime_timestamp()
723 * Convert abstime to timestamp.
726 abstime_timestamp(PG_FUNCTION_ARGS)
728 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
733 char zone[MAXDATELEN + 1],
738 case INVALID_ABSTIME:
739 elog(ERROR, "Unable to convert abstime 'invalid' to timestamp");
740 TIMESTAMP_NOBEGIN(result);
743 case NOSTART_ABSTIME:
744 TIMESTAMP_NOBEGIN(result);
748 TIMESTAMP_NOEND(result);
752 abstime2tm(abstime, &tz, tm, &tzn);
753 if (tm2timestamp(tm, 0, NULL, &result) != 0)
754 elog(ERROR, "Unable convert ABSTIME to TIMESTAMP"
755 "\n\tabstime_timestamp() internal error");
759 PG_RETURN_TIMESTAMP(result);
763 /* timestamptz_abstime()
764 * Convert timestamp with time zone to abstime.
767 timestamptz_abstime(PG_FUNCTION_ARGS)
769 TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
775 if (TIMESTAMP_IS_NOBEGIN(timestamp))
776 result = NOSTART_ABSTIME;
777 else if (TIMESTAMP_IS_NOEND(timestamp))
778 result = NOEND_ABSTIME;
779 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
780 result = tm2abstime(tm, 0);
783 elog(ERROR, "Unable to convert timestamp to abstime");
784 result = INVALID_ABSTIME;
787 PG_RETURN_ABSOLUTETIME(result);
790 /* abstime_timestamptz()
791 * Convert abstime to timestamp.
794 abstime_timestamptz(PG_FUNCTION_ARGS)
796 AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
801 char zone[MAXDATELEN + 1],
806 case INVALID_ABSTIME:
807 elog(ERROR, "Unable to convert abstime 'invalid' to timestamptz");
808 TIMESTAMP_NOBEGIN(result);
811 case NOSTART_ABSTIME:
812 TIMESTAMP_NOBEGIN(result);
816 TIMESTAMP_NOEND(result);
820 abstime2tm(abstime, &tz, tm, &tzn);
821 if (tm2timestamp(tm, 0, &tz, &result) != 0)
822 elog(ERROR, "Unable convert ABSTIME to TIMESTAMP WITH TIME ZONE"
823 "\n\tabstime_timestamp() internal error");
827 PG_RETURN_TIMESTAMP(result);
831 /*****************************************************************************
832 * USER I/O ROUTINES *
833 *****************************************************************************/
836 * reltimein - converts a reltime string in an internal format
839 reltimein(PG_FUNCTION_ARGS)
841 char *str = PG_GETARG_CSTRING(0);
847 char *field[MAXDATEFIELDS];
849 ftype[MAXDATEFIELDS];
850 char lowstr[MAXDATELEN + 1];
852 if (strlen(str) > MAXDATELEN)
853 elog(ERROR, "Bad (length) reltime external representation '%s'", str);
855 if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
856 || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
857 elog(ERROR, "Bad reltime external representation '%s'", str);
862 result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
863 result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
867 elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
868 result = INVALID_RELTIME;
872 PG_RETURN_RELATIVETIME(result);
877 * reltimeout - converts the internal format to a reltime string
880 reltimeout(PG_FUNCTION_ARGS)
882 RelativeTime time = PG_GETARG_RELATIVETIME(0);
886 char buf[MAXDATELEN + 1];
888 reltime2tm(time, tm);
889 EncodeInterval(tm, 0, DateStyle, buf);
891 result = pstrdup(buf);
892 PG_RETURN_CSTRING(result);
897 reltime2tm(RelativeTime time, struct tm * tm)
899 TMODULO(time, tm->tm_year, 31557600);
900 TMODULO(time, tm->tm_mon, 2592000);
901 TMODULO(time, tm->tm_mday, 86400);
902 TMODULO(time, tm->tm_hour, 3600);
903 TMODULO(time, tm->tm_min, 60);
904 TMODULO(time, tm->tm_sec, 1);
911 * tintervalin - converts an interval string to internal format
914 tintervalin(PG_FUNCTION_ARGS)
916 char *intervalstr = PG_GETARG_CSTRING(0);
917 TimeInterval interval;
918 AbsoluteTime i_start,
923 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
924 if (istinterval(intervalstr, &t1, &t2) == 0)
925 elog(ERROR, "Unable to decode tinterval '%s'", intervalstr);
927 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
928 interval->status = T_INTERVAL_INVAL; /* undefined */
930 interval->status = T_INTERVAL_VALID;
932 i_start = ABSTIMEMIN(t1, t2);
933 i_end = ABSTIMEMAX(t1, t2);
934 interval->data[0] = i_start;
935 interval->data[1] = i_end;
937 PG_RETURN_TIMEINTERVAL(interval);
942 * tintervalout - converts an internal interval format to a string
946 tintervalout(PG_FUNCTION_ARGS)
948 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
952 i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
953 strcpy(i_str, "[\"");
954 if (interval->status == T_INTERVAL_INVAL)
955 strcat(i_str, INVALID_INTERVAL_STR);
958 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
959 AbsoluteTimeGetDatum(interval->data[0])));
962 strcat(i_str, "\" \"");
963 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
964 AbsoluteTimeGetDatum(interval->data[1])));
968 strcat(i_str, "\"]\0");
969 PG_RETURN_CSTRING(i_str);
973 /*****************************************************************************
975 *****************************************************************************/
978 interval_reltime(PG_FUNCTION_ARGS)
980 Interval *interval = PG_GETARG_INTERVAL_P(0);
984 #ifdef HAVE_INT64_TIMESTAMP
990 if (interval->month == 0)
995 else if (abs(interval->month) >= 12)
997 year = (interval->month / 12);
998 month = (interval->month % 12);
1003 month = interval->month;
1006 #ifdef HAVE_INT64_TIMESTAMP
1007 span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
1008 * INT64CONST(86400)) + interval->time);
1009 span /= INT64CONST(1000000);
1011 span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
1014 if ((span < INT_MIN) || (span > INT_MAX))
1015 time = INVALID_RELTIME;
1019 PG_RETURN_RELATIVETIME(time);
1024 reltime_interval(PG_FUNCTION_ARGS)
1026 RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
1031 result = (Interval *) palloc(sizeof(Interval));
1035 case INVALID_RELTIME:
1036 elog(ERROR, "Unable to convert reltime 'invalid' to interval");
1042 #ifdef HAVE_INT64_TIMESTAMP
1043 year = (reltime / (36525 * 864));
1044 reltime -= (year * (36525 * 864));
1045 month = (reltime / (30 * 86400));
1046 reltime -= (month * (30 * 86400));
1048 result->time = (reltime * INT64CONST(1000000));
1050 TMODULO(reltime, year, (36525 * 864));
1051 TMODULO(reltime, month, (30 * 86400));
1053 result->time = reltime;
1055 result->month = ((12 * year) + month);
1059 PG_RETURN_INTERVAL_P(result);
1064 * mktinterval - creates a time interval with endpoints t1 and t2
1067 mktinterval(PG_FUNCTION_ARGS)
1069 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1070 AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
1071 AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
1072 AbsoluteTime tend = ABSTIMEMAX(t1, t2);
1073 TimeInterval interval;
1075 interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
1077 if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
1078 interval->status = T_INTERVAL_INVAL;
1081 interval->status = T_INTERVAL_VALID;
1082 interval->data[0] = tstart;
1083 interval->data[1] = tend;
1086 PG_RETURN_TIMEINTERVAL(interval);
1090 * timepl, timemi and abstimemi use the formula
1091 * abstime + reltime = abstime
1092 * so abstime - reltime = abstime
1093 * and abstime - abstime = reltime
1097 * timepl - returns the value of (abstime t1 + reltime t2)
1100 timepl(PG_FUNCTION_ARGS)
1102 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1103 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1105 if (AbsoluteTimeIsReal(t1) &&
1106 RelativeTimeIsValid(t2) &&
1107 ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
1108 : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
1109 PG_RETURN_ABSOLUTETIME(t1 + t2);
1111 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1116 * timemi - returns the value of (abstime t1 - reltime t2)
1119 timemi(PG_FUNCTION_ARGS)
1121 AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
1122 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1124 if (AbsoluteTimeIsReal(t1) &&
1125 RelativeTimeIsValid(t2) &&
1126 ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
1127 : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
1128 PG_RETURN_ABSOLUTETIME(t1 - t2);
1130 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1135 * intinterval - returns true iff absolute date is in the interval
1138 intinterval(PG_FUNCTION_ARGS)
1140 AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
1141 TimeInterval interval = PG_GETARG_TIMEINTERVAL(1);
1143 if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1145 if (DatumGetBool(DirectFunctionCall2(abstimege,
1146 AbsoluteTimeGetDatum(t),
1147 AbsoluteTimeGetDatum(interval->data[0]))) &&
1148 DatumGetBool(DirectFunctionCall2(abstimele,
1149 AbsoluteTimeGetDatum(t),
1150 AbsoluteTimeGetDatum(interval->data[1]))))
1151 PG_RETURN_BOOL(true);
1153 PG_RETURN_BOOL(false);
1157 * tintervalrel - returns relative time corresponding to interval
1160 tintervalrel(PG_FUNCTION_ARGS)
1162 TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1163 AbsoluteTime t1 = interval->data[0];
1164 AbsoluteTime t2 = interval->data[1];
1166 if (interval->status != T_INTERVAL_VALID)
1167 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1169 if (AbsoluteTimeIsReal(t1) &&
1170 AbsoluteTimeIsReal(t2))
1171 PG_RETURN_RELATIVETIME(t2 - t1);
1173 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1178 * timenow - returns time "now", internal format
1180 * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1183 timenow(PG_FUNCTION_ARGS)
1188 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1190 PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1194 * reltimeeq - returns true iff arguments are equal
1195 * reltimene - returns true iff arguments are not equal
1196 * reltimelt - returns true iff t1 less than t2
1197 * reltimegt - returns true iff t1 greater than t2
1198 * reltimele - returns true iff t1 less than or equal to t2
1199 * reltimege - returns true iff t1 greater than or equal to t2
1202 reltimeeq(PG_FUNCTION_ARGS)
1204 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1205 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1207 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1208 PG_RETURN_BOOL(false);
1209 PG_RETURN_BOOL(t1 == t2);
1213 reltimene(PG_FUNCTION_ARGS)
1215 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1216 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1218 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1219 PG_RETURN_BOOL(false);
1220 PG_RETURN_BOOL(t1 != t2);
1224 reltimelt(PG_FUNCTION_ARGS)
1226 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1227 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1229 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1230 PG_RETURN_BOOL(false);
1231 PG_RETURN_BOOL(t1 < t2);
1235 reltimegt(PG_FUNCTION_ARGS)
1237 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1238 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1240 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1241 PG_RETURN_BOOL(false);
1242 PG_RETURN_BOOL(t1 > t2);
1246 reltimele(PG_FUNCTION_ARGS)
1248 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1249 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1251 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1252 PG_RETURN_BOOL(false);
1253 PG_RETURN_BOOL(t1 <= t2);
1257 reltimege(PG_FUNCTION_ARGS)
1259 RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1260 RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1262 if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1263 PG_RETURN_BOOL(false);
1264 PG_RETURN_BOOL(t1 >= t2);
1269 * tintervalsame - returns true iff interval i1 is same as interval i2
1270 * Check begin and end time.
1273 tintervalsame(PG_FUNCTION_ARGS)
1275 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1276 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1278 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1279 PG_RETURN_BOOL(false);
1281 if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1282 AbsoluteTimeGetDatum(i1->data[0]),
1283 AbsoluteTimeGetDatum(i2->data[0]))) &&
1284 DatumGetBool(DirectFunctionCall2(abstimeeq,
1285 AbsoluteTimeGetDatum(i1->data[1]),
1286 AbsoluteTimeGetDatum(i2->data[1]))))
1287 PG_RETURN_BOOL(true);
1288 PG_RETURN_BOOL(false);
1293 * tintervaleq - returns true iff interval i1 is equal to interval i2
1294 * Check length of intervals.
1297 tintervaleq(PG_FUNCTION_ARGS)
1299 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1300 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1306 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1307 PG_RETURN_BOOL(false);
1314 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1315 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1316 PG_RETURN_BOOL(false);
1318 PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
1322 tintervalne(PG_FUNCTION_ARGS)
1324 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1325 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1331 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1332 PG_RETURN_BOOL(false);
1339 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1340 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1341 PG_RETURN_BOOL(false);
1343 PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
1347 tintervallt(PG_FUNCTION_ARGS)
1349 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1350 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1356 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1357 PG_RETURN_BOOL(false);
1364 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1365 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1366 PG_RETURN_BOOL(false);
1368 PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
1372 tintervalle(PG_FUNCTION_ARGS)
1374 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1375 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1381 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1382 PG_RETURN_BOOL(false);
1389 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1390 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1391 PG_RETURN_BOOL(false);
1393 PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
1397 tintervalgt(PG_FUNCTION_ARGS)
1399 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1400 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1406 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1407 PG_RETURN_BOOL(false);
1414 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1415 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1416 PG_RETURN_BOOL(false);
1418 PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
1422 tintervalge(PG_FUNCTION_ARGS)
1424 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1425 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1431 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1432 PG_RETURN_BOOL(false);
1439 if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
1440 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1441 PG_RETURN_BOOL(false);
1443 PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
1448 * tintervalleneq - returns true iff length of interval i is equal to
1450 * tintervallenne - returns true iff length of interval i is not equal
1452 * tintervallenlt - returns true iff length of interval i is less than
1454 * tintervallengt - returns true iff length of interval i is greater
1456 * tintervallenle - returns true iff length of interval i is less or
1457 * equal than reltime t
1458 * tintervallenge - returns true iff length of interval i is greater or
1459 * equal than reltime t
1462 tintervalleneq(PG_FUNCTION_ARGS)
1464 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1465 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1468 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1469 PG_RETURN_BOOL(false);
1470 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1471 TimeIntervalGetDatum(i)));
1472 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
1476 tintervallenne(PG_FUNCTION_ARGS)
1478 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1479 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1482 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1483 PG_RETURN_BOOL(false);
1484 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1485 TimeIntervalGetDatum(i)));
1486 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
1490 tintervallenlt(PG_FUNCTION_ARGS)
1492 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1493 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1496 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1497 PG_RETURN_BOOL(false);
1498 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1499 TimeIntervalGetDatum(i)));
1500 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
1504 tintervallengt(PG_FUNCTION_ARGS)
1506 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1507 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1510 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1511 PG_RETURN_BOOL(false);
1512 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1513 TimeIntervalGetDatum(i)));
1514 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
1518 tintervallenle(PG_FUNCTION_ARGS)
1520 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1521 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1524 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1525 PG_RETURN_BOOL(false);
1526 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1527 TimeIntervalGetDatum(i)));
1528 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
1532 tintervallenge(PG_FUNCTION_ARGS)
1534 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1535 RelativeTime t = PG_GETARG_RELATIVETIME(1);
1538 if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1539 PG_RETURN_BOOL(false);
1540 rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1541 TimeIntervalGetDatum(i)));
1542 PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
1546 * tintervalct - returns true iff interval i1 contains interval i2
1549 tintervalct(PG_FUNCTION_ARGS)
1551 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1552 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1554 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1555 PG_RETURN_BOOL(false);
1556 if (DatumGetBool(DirectFunctionCall2(abstimele,
1557 AbsoluteTimeGetDatum(i1->data[0]),
1558 AbsoluteTimeGetDatum(i2->data[0]))) &&
1559 DatumGetBool(DirectFunctionCall2(abstimege,
1560 AbsoluteTimeGetDatum(i1->data[1]),
1561 AbsoluteTimeGetDatum(i2->data[1]))))
1562 PG_RETURN_BOOL(true);
1563 PG_RETURN_BOOL(false);
1567 * tintervalov - returns true iff interval i1 (partially) overlaps i2
1570 tintervalov(PG_FUNCTION_ARGS)
1572 TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1573 TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1575 if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1576 PG_RETURN_BOOL(false);
1577 if (DatumGetBool(DirectFunctionCall2(abstimelt,
1578 AbsoluteTimeGetDatum(i1->data[1]),
1579 AbsoluteTimeGetDatum(i2->data[0]))) ||
1580 DatumGetBool(DirectFunctionCall2(abstimegt,
1581 AbsoluteTimeGetDatum(i1->data[0]),
1582 AbsoluteTimeGetDatum(i2->data[1]))))
1583 PG_RETURN_BOOL(false);
1584 PG_RETURN_BOOL(true);
1588 * tintervalstart - returns the start of interval i
1591 tintervalstart(PG_FUNCTION_ARGS)
1593 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1595 if (i->status == T_INTERVAL_INVAL)
1596 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1597 PG_RETURN_ABSOLUTETIME(i->data[0]);
1601 * tintervalend - returns the end of interval i
1604 tintervalend(PG_FUNCTION_ARGS)
1606 TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1608 if (i->status == T_INTERVAL_INVAL)
1609 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1610 PG_RETURN_ABSOLUTETIME(i->data[1]);
1614 /*****************************************************************************
1615 * PRIVATE ROUTINES *
1616 *****************************************************************************/
1619 * istinterval - returns 1, iff i_string is a valid interval descr.
1620 * 0, iff i_string is NOT a valid interval desc.
1621 * 2, iff any time is INVALID_ABSTIME
1624 * i_start, i_end: interval margins
1627 * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1629 * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
1631 * where <AbsTime> satisfies the syntax of absolute time.
1633 * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
1636 istinterval(char *i_string,
1637 AbsoluteTime *i_start,
1638 AbsoluteTime *i_end)
1645 /* skip leading blanks up to '[' */
1646 while ((c = *p) != '\0')
1651 return 0; /* syntax error */
1656 /* skip leading blanks up to "'" */
1657 while ((c = *p) != '\0')
1662 return 0; /* syntax error */
1667 if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1668 return 0; /* undefined range, handled like a syntax
1670 /* search for the end of the first date and change it to a NULL */
1672 while ((c = *p1) != '\0')
1681 /* get the first date */
1682 *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1683 CStringGetDatum(p)));
1684 /* rechange NULL at the end of the first date to a "'" */
1687 /* skip blanks up to "'", beginning of second date */
1688 while ((c = *p) != '\0')
1693 return 0; /* syntax error */
1698 /* search for the end of the second date and change it to a NULL */
1700 while ((c = *p1) != '\0')
1709 /* get the second date */
1710 *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1711 CStringGetDatum(p)));
1712 /* rechange NULL at the end of the first date to a ''' */
1715 /* skip blanks up to ']' */
1716 while ((c = *p) != '\0')
1721 return 0; /* syntax error */
1728 return 0; /* syntax error */
1729 /* it seems to be a valid interval */
1734 /*****************************************************************************
1736 *****************************************************************************/
1739 int4reltime(PG_FUNCTION_ARGS)
1741 int32 timevalue = PG_GETARG_INT32(0);
1743 /* Just coerce it directly to RelativeTime ... */
1744 PG_RETURN_RELATIVETIME((RelativeTime) timevalue);
1749 * returns the current time as a text. similar to timenow() but returns
1750 * seconds with more precision (up to microsecs). (I need this to compare
1751 * the Wisconsin benchmark with Illustra whose TimeNow() shows current
1752 * time with precision up to microsecs.) - ay 3/95
1755 timeofday(PG_FUNCTION_ARGS)
1758 struct timezone tpz;
1764 gettimeofday(&tp, &tpz);
1765 strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1766 localtime((time_t *) &tp.tv_sec));
1767 snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1769 len = VARHDRSZ + strlen(buf);
1770 result = (text *) palloc(len);
1771 VARATT_SIZEP(result) = len;
1772 memcpy(VARDATA(result), buf, strlen(buf));
1773 PG_RETURN_TEXT_P(result);