diff options
Diffstat (limited to 'src/backend/utils/adt/date.c')
-rw-r--r-- | src/backend/utils/adt/date.c | 1466 |
1 files changed, 361 insertions, 1105 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 4ca3850f790..7102f64a44f 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -1,1303 +1,559 @@ /*------------------------------------------------------------------------- * * date.c - * Utilities for the built-in type "AbsoluteTime" (defined in nabstime). - * Functions for the built-in type "RelativeTime". - * Functions for the built-in type "TimeInterval". + * implements DATE and TIME data types specified in SQL-92 standard * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 1994-5, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.41 2000/01/26 05:57:13 momjian Exp $ - * - * NOTES - * This code is actually (almost) unused. - * It needs to be integrated with Time and struct trange. - * - * XXX This code needs to be rewritten to work with the "new" definitions - * XXX in h/tim.h. Look for int32's, int, long, etc. in the code. The - * XXX definitions in h/tim.h may need to be rethought also. - * - * XXX This code has been cleaned up some - avi 07/07/93 + * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.42 2000/02/16 18:17:02 thomas Exp $ * *------------------------------------------------------------------------- */ -#include <ctype.h> -#include <time.h> -#include <sys/time.h> -#include <sys/types.h> +#include <limits.h> #include "postgres.h" #ifdef HAVE_FLOAT_H #include <float.h> #endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#ifndef MAXINT -#define MAXINT INT_MAX -#endif -#else -#ifdef HAVE_VALUES_H -#include <values.h> -#endif -#endif - -#include "access/xact.h" #include "miscadmin.h" #include "utils/builtins.h" -#include "utils/dt.h" - -#define INVALID_RELTIME_STR "Undefined RelTime" -#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1) -#define RELTIME_LABEL '@' -#define RELTIME_PAST "ago" -#define DIRMAXLEN (sizeof(RELTIME_PAST)-1) - -/* - * Unix epoch is Jan 1 00:00:00 1970. Postgres knows about times - * sixty-eight years on either side of that. - */ - -#define IsSpace(C) ((C) == ' ') - -#define T_INTERVAL_INVAL 0 /* data represents no valid interval */ -#define T_INTERVAL_VALID 1 /* data represents a valid interval */ -/* - * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST'] - * 0 1 2 3 4 5 6 - * 1234567890123456789012345678901234567890123456789012345678901234 - * - * we allocate some extra -- timezones are usually 3 characters but - * this is not in the POSIX standard... - */ -#define T_INTERVAL_LEN 80 -#define INVALID_INTERVAL_STR "Undefined Range" -#define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1) - -#define ABSTIMEMIN(t1, t2) abstimele((t1),(t2)) ? (t1) : (t2) -#define ABSTIMEMAX(t1, t2) abstimelt((t1),(t2)) ? (t2) : (t1) - -#ifdef NOT_USED -static char *unit_tab[] = { - "second", "seconds", "minute", "minutes", - "hour", "hours", "day", "days", "week", "weeks", -"month", "months", "year", "years"}; - -#define UNITMAXLEN 7 /* max length of a unit name */ -#define NUNITS 14 /* number of different units */ - -/* table of seconds per unit (month = 30 days, year = 365 days) */ -static int sec_tab[] = { - 1, 1, 60, 60, - 3600, 3600, 86400, 86400, 604800, 604800, -2592000, 2592000, 31536000, 31536000}; - -#endif - -/* - * Function prototypes -- internal to this file only - */ -static void reltime2tm(RelativeTime time, struct tm * tm); - -#ifdef NOT_USED -static int correct_unit(char *unit, int *unptr); -static int correct_dir(char *direction, int *signptr); - -#endif +static int +date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn); -static int istinterval(char *i_string, - AbsoluteTime *i_start, - AbsoluteTime *i_end); /***************************************************************************** - * USER I/O ROUTINES * + * Date ADT *****************************************************************************/ -/* - * reltimein - converts a reltime string in an internal format + +/* date_in() + * Given date text string, convert to internal date format. */ -RelativeTime -reltimein(char *str) +DateADT +date_in(char *str) { - RelativeTime result; - + DateADT date; + double fsec; struct tm tt, *tm = &tt; - double fsec; + int tzp; int dtype; + int nf; char *field[MAXDATEFIELDS]; - int nf, - ftype[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; char lowstr[MAXDATELEN + 1]; if (!PointerIsValid(str)) elog(ERROR, "Bad (null) date external representation"); - if (strlen(str) > MAXDATELEN) - elog(ERROR, "Bad (length) reltime external representation '%s'", str); - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) - elog(ERROR, "Bad reltime external representation '%s'", str); + || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0)) + elog(ERROR, "Bad date external representation '%s'", str); switch (dtype) { - case DTK_DELTA: - result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec); - result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60)); - return result; + case DTK_DATE: + break; + + case DTK_CURRENT: + GetCurrentTime(tm); + break; + + case DTK_EPOCH: + tm->tm_year = 1970; + tm->tm_mon = 1; + tm->tm_mday = 1; + break; default: - return INVALID_RELTIME; + elog(ERROR, "Unrecognized date external representation '%s'", str); } - elog(ERROR, "Bad reltime (internal coding error) '%s'", str); - return INVALID_RELTIME; -} /* reltimein() */ + date = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1)); + return date; +} /* date_in() */ -/* - * reltimeout - converts the internal format to a reltime string +/* date_out() + * Given internal format date, convert to text string. */ char * -reltimeout(RelativeTime time) +date_out(DateADT date) { char *result; struct tm tt, *tm = &tt; char buf[MAXDATELEN + 1]; - if (time == INVALID_RELTIME) - { - strcpy(buf, INVALID_RELTIME_STR); + j2date((date + date2j(2000, 1, 1)), + &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); - } - else - { - reltime2tm(time, tm); - EncodeTimeSpan(tm, 0, DateStyle, buf); - } + EncodeDateOnly(tm, DateStyle, buf); result = palloc(strlen(buf) + 1); + strcpy(result, buf); return result; -} /* reltimeout() */ - - -#define TMODULO(t,q,u) \ -do { \ - q = (t / u); \ - if (q != 0) t -= (q * u); \ -} while(0) - -static void -reltime2tm(RelativeTime time, struct tm * tm) -{ - TMODULO(time, tm->tm_year, 31536000); - TMODULO(time, tm->tm_mon, 2592000); - TMODULO(time, tm->tm_mday, 86400); - TMODULO(time, tm->tm_hour, 3600); - TMODULO(time, tm->tm_min, 60); - TMODULO(time, tm->tm_sec, 1); - - return; -} /* reltime2tm() */ +} /* date_out() */ -#ifdef NOT_USED -int -dummyfunc() +bool +date_eq(DateADT dateVal1, DateADT dateVal2) { - char *timestring; - long quantity; - int i; - int unitnr; - - timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR), - UNITMAXLEN) + 1); - if (timevalue == INVALID_RELTIME) - { - strcpy(timestring, INVALID_RELTIME_STR); - return timestring; - } - - if (timevalue == 0) - i = 1; /* unit = 'seconds' */ - else - for (i = 12; i >= 0; i = i - 2) - if ((timevalue % sec_tab[i]) == 0) - break; /* appropriate unit found */ - unitnr = i; - quantity = (timevalue / sec_tab[unitnr]); - if (quantity > 1 || quantity < -1) - unitnr++; /* adjust index for PLURAL of unit */ - if (quantity >= 0) - sprintf(timestring, "%c %lu %s", RELTIME_LABEL, - quantity, unit_tab[unitnr]); - else - sprintf(timestring, "%c %lu %s %s", RELTIME_LABEL, - (quantity * -1), unit_tab[unitnr], RELTIME_PAST); - return timestring; + return dateVal1 == dateVal2; } -#endif - - -/* - * tintervalin - converts an interval string to an internal format - */ -TimeInterval -tintervalin(char *intervalstr) +bool +date_ne(DateADT dateVal1, DateADT dateVal2) { - int error; - AbsoluteTime i_start, - i_end, - t1, - t2; - TimeInterval interval; - - interval = (TimeInterval) palloc(sizeof(TimeIntervalData)); - error = istinterval(intervalstr, &t1, &t2); - if (error == 0) - interval->status = T_INTERVAL_INVAL; - if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) - interval->status = T_INTERVAL_INVAL; /* undefined */ - else - { - i_start = ABSTIMEMIN(t1, t2); - i_end = ABSTIMEMAX(t1, t2); - interval->data[0] = i_start; - interval->data[1] = i_end; - interval->status = T_INTERVAL_VALID; - } - return interval; + return dateVal1 != dateVal2; } - -/* - * tintervalout - converts an internal interval format to a string - * - */ -char * -tintervalout(TimeInterval interval) +bool +date_lt(DateADT dateVal1, DateADT dateVal2) { - char *i_str, - *p; - - i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */ - strcpy(i_str, "[\""); - if (interval->status == T_INTERVAL_INVAL) - strcat(i_str, INVALID_INTERVAL_STR); - else - { - p = nabstimeout(interval->data[0]); - strcat(i_str, p); - pfree(p); - strcat(i_str, "\" \""); - p = nabstimeout(interval->data[1]); - strcat(i_str, p); - pfree(p); - } - strcat(i_str, "\"]\0"); - return i_str; -} - - -/***************************************************************************** - * PUBLIC ROUTINES * - *****************************************************************************/ + return dateVal1 < dateVal2; +} /* date_lt() */ -RelativeTime -timespan_reltime(TimeSpan *timespan) +bool +date_le(DateADT dateVal1, DateADT dateVal2) { - RelativeTime time; - int year, - month; - double span; - - if (!PointerIsValid(timespan)) - time = INVALID_RELTIME; - - if (TIMESPAN_IS_INVALID(*timespan)) - { - time = INVALID_RELTIME; - - } - else - { - if (timespan->month == 0) - { - year = 0; - month = 0; - - } - else if (abs(timespan->month) >= 12) - { - year = (timespan->month / 12); - month = (timespan->month % 12); - - } - else - { - year = 0; - month = timespan->month; - } - - span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + timespan->time); - - time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME); - } + return dateVal1 <= dateVal2; +} /* date_le() */ - return time; -} /* timespan_reltime() */ - - -TimeSpan * -reltime_timespan(RelativeTime reltime) +bool +date_gt(DateADT dateVal1, DateADT dateVal2) { - TimeSpan *result; - int year, - month; - - if (!PointerIsValid(result = palloc(sizeof(TimeSpan)))) - elog(ERROR, "Memory allocation failed, can't convert reltime to timespan"); - - switch (reltime) - { - case INVALID_RELTIME: - TIMESPAN_INVALID(*result); - break; - - default: - TMODULO(reltime, year, 31536000); - TMODULO(reltime, month, 2592000); - - result->time = reltime; - result->month = ((12 * year) + month); - } - - return result; -} /* reltime_timespan() */ + return dateVal1 > dateVal2; +} /* date_gt() */ +bool +date_ge(DateADT dateVal1, DateADT dateVal2) +{ + return dateVal1 >= dateVal2; +} /* date_ge() */ -/* - * mktinterval - creates a time interval with endpoints t1 and t2 - */ -TimeInterval -mktinterval(AbsoluteTime t1, AbsoluteTime t2) +int +date_cmp(DateADT dateVal1, DateADT dateVal2) { - AbsoluteTime tstart = ABSTIMEMIN(t1, t2), - tend = ABSTIMEMAX(t1, t2); - TimeInterval interval; + if (dateVal1 < dateVal2) + return -1; + else if (dateVal1 > dateVal2) + return 1; + return 0; +} /* date_cmp() */ - interval = (TimeInterval) palloc(sizeof(TimeIntervalData)); - if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) - interval->status = T_INTERVAL_INVAL; - else - { - interval->status = T_INTERVAL_VALID; - interval->data[0] = tstart; - interval->data[1] = tend; - } +DateADT +date_larger(DateADT dateVal1, DateADT dateVal2) +{ + return date_gt(dateVal1, dateVal2) ? dateVal1 : dateVal2; +} /* date_larger() */ - return interval; -} +DateADT +date_smaller(DateADT dateVal1, DateADT dateVal2) +{ + return date_lt(dateVal1, dateVal2) ? dateVal1 : dateVal2; +} /* date_smaller() */ -/* - * timepl, timemi and abstimemi use the formula - * abstime + reltime = abstime - * so abstime - reltime = abstime - * and abstime - abstime = reltime +/* Compute difference between two dates in days. */ +int4 +date_mi(DateADT dateVal1, DateADT dateVal2) +{ + return dateVal1 - dateVal2; +} /* date_mi() */ -/* - * timepl - returns the value of (abstime t1 + relime t2) +/* Add a number of days to a date, giving a new date. + * Must handle both positive and negative numbers of days. */ -AbsoluteTime -timepl(AbsoluteTime t1, RelativeTime t2) +DateADT +date_pli(DateADT dateVal, int4 days) { - if (t1 == CURRENT_ABSTIME) - t1 = GetCurrentTransactionStartTime(); - - if (AbsoluteTimeIsReal(t1) && - RelativeTimeIsValid(t2) && - ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2) - : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */ - return t1 + t2; + return dateVal + days; +} /* date_pli() */ - return INVALID_ABSTIME; -} - - -/* - * timemi - returns the value of (abstime t1 - reltime t2) +/* Subtract a number of days from a date, giving a new date. */ -AbsoluteTime -timemi(AbsoluteTime t1, RelativeTime t2) +DateADT +date_mii(DateADT dateVal, int4 days) { - if (t1 == CURRENT_ABSTIME) - t1 = GetCurrentTransactionStartTime(); - - if (AbsoluteTimeIsReal(t1) && - RelativeTimeIsValid(t2) && - ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2) - : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */ - return t1 - t2; - - return INVALID_ABSTIME; -} + return date_pli(dateVal, -days); +} /* date_mii() */ -/* - * abstimemi - returns the value of (abstime t1 - abstime t2) +/* date_timestamp() + * Convert date to timestamp data type. */ -static RelativeTime -abstimemi(AbsoluteTime t1, AbsoluteTime t2) +Timestamp * +date_timestamp(DateADT dateVal) { - if (t1 == CURRENT_ABSTIME) - t1 = GetCurrentTransactionStartTime(); - if (t2 == CURRENT_ABSTIME) - t2 = GetCurrentTransactionStartTime(); + Timestamp *result; + struct tm tt, + *tm = &tt; + int tz; + double fsec = 0; + char *tzn; - if (AbsoluteTimeIsReal(t1) && - AbsoluteTimeIsReal(t2)) - return t1 - t2; + result = palloc(sizeof(Timestamp)); - return INVALID_RELTIME; -} + if (date2tm(dateVal, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to convert date to timestamp"); + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "Timestamp out of range"); -/* - * ininterval - returns 1, iff absolute date is in the interval - */ -int -ininterval(AbsoluteTime t, TimeInterval interval) -{ - if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME) - return (abstimege(t, interval->data[0]) && - abstimele(t, interval->data[1])); - return 0; -} + return result; +} /* date_timestamp() */ -/* - * intervalrel - returns relative time corresponding to interval - */ -RelativeTime -intervalrel(TimeInterval interval) -{ - if (interval->status == T_INTERVAL_VALID) - return abstimemi(interval->data[1], interval->data[0]); - else - return INVALID_RELTIME; -} -/* - * timenow - returns time "now", internal format - * - * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992 +/* timestamp_date() + * Convert timestamp to date data type. */ -AbsoluteTime -timenow() +DateADT +timestamp_date(Timestamp *timestamp) { - time_t sec; + DateADT result; + struct tm tt, + *tm = &tt; + int tz; + double fsec; + char *tzn; - if (time(&sec) < 0) - return INVALID_ABSTIME; - return (AbsoluteTime) sec; -} + if (!PointerIsValid(timestamp)) + elog(ERROR, "Unable to convert null timestamp to date"); -/* - * reltimeeq - returns 1, iff arguments are equal - * reltimene - returns 1, iff arguments are not equal - * reltimelt - returns 1, iff t1 less than t2 - * reltimegt - returns 1, iff t1 greater than t2 - * reltimele - returns 1, iff t1 less than or equal to t2 - * reltimege - returns 1, iff t1 greater than or equal to t2 - */ -bool -reltimeeq(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 == t2; -} + if (TIMESTAMP_NOT_FINITE(*timestamp)) + elog(ERROR, "Unable to convert timestamp to date"); -bool -reltimene(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 != t2; -} + if (TIMESTAMP_IS_EPOCH(*timestamp)) + { + timestamp2tm(SetTimestamp(*timestamp), NULL, tm, &fsec, NULL); -bool -reltimelt(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 < t2; -} + } + else if (TIMESTAMP_IS_CURRENT(*timestamp)) + { + timestamp2tm(SetTimestamp(*timestamp), &tz, tm, &fsec, &tzn); -bool -reltimegt(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 > t2; -} + } + else + { + if (timestamp2tm(*timestamp, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to convert timestamp to date"); + } -bool -reltimele(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 <= t2; -} + result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1)); -bool -reltimege(RelativeTime t1, RelativeTime t2) -{ - if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) - return 0; - return t1 >= t2; -} + return result; +} /* timestamp_date() */ -/* - * intervalsame - returns 1, iff interval i1 is same as interval i2 - * Check begin and end time. +/* abstime_date() + * Convert abstime to date data type. */ -bool -intervalsame(TimeInterval i1, TimeInterval i2) +DateADT +abstime_date(AbsoluteTime abstime) { - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ - return (abstimeeq(i1->data[0], i2->data[0]) && - abstimeeq(i1->data[1], i2->data[1])); -} /* intervalsame() */ + DateADT result; + struct tm tt, + *tm = &tt; + int tz; + switch (abstime) + { + case INVALID_ABSTIME: + case NOSTART_ABSTIME: + case NOEND_ABSTIME: + elog(ERROR, "Unable to convert reserved abstime value to date"); + + /* + * pretend to drop through to make compiler think that result + * will be set + */ + + case EPOCH_ABSTIME: + result = date2j(1970, 1, 1) - date2j(2000, 1, 1); + break; -/* - * intervaleq - returns 1, iff interval i1 is equal to interval i2 - * Check length of intervals. - */ -bool -intervaleq(TimeInterval i1, TimeInterval i2) -{ - AbsoluteTime t10, - t11, - t20, - t21; + case CURRENT_ABSTIME: + GetCurrentTime(tm); + result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); + break; - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ + default: + abstime2tm(abstime, &tz, tm, NULL); + result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); + break; + } - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + return result; +} /* abstime_date() */ - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); - - return (t11 - t10) == (t21 - t20); -} /* intervaleq() */ - -/* - * intervalne - returns 1, iff interval i1 is not equal to interval i2 - * Check length of intervals. +/* date2tm() + * Convert date to time structure. + * Note that date is an implicit local time, but the system calls assume + * that everything is GMT. So, convert to GMT, rotate to local time, + * and then convert again to try to get the time zones correct. */ -bool -intervalne(TimeInterval i1, TimeInterval i2) +static int +date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn) { - AbsoluteTime t10, - t11, - t20, - t21; + struct tm *tx; + time_t utime; - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ + *fsec = 0; - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + tm->tm_isdst = -1; - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; + if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + { - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); - - return (t11 - t10) != (t21 - t20); -} /* intervalne() */ - -/* - * intervallt - returns TRUE, iff interval i1 is less than interval i2 - * Check length of intervals. - */ -bool -intervallt(TimeInterval i1, TimeInterval i2) -{ - AbsoluteTime t10, - t11, - t20, - t21; + /* convert to system time */ + utime = ((dateVal + (date2j(2000, 1, 1) - date2j(1970, 1, 1))) * 86400); + /* rotate to noon to get the right day in time zone */ + utime += (12 * 60 * 60); + +#ifdef USE_POSIX_TIME + tx = localtime(&utime); + + tm->tm_year = tx->tm_year + 1900; + tm->tm_mon = tx->tm_mon + 1; + tm->tm_mday = tx->tm_mday; + tm->tm_isdst = tx->tm_isdst; + +#if defined(HAVE_TM_ZONE) + tm->tm_gmtoff = tx->tm_gmtoff; + tm->tm_zone = tx->tm_zone; + + /* tm_gmtoff is Sun/DEC-ism */ + *tzp = -(tm->tm_gmtoff); + if (tzn != NULL) + *tzn = (char *) tm->tm_zone; +#elif defined(HAVE_INT_TIMEZONE) +#ifdef __CYGWIN__ + *tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone); +#else + *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone); +#endif + if (tzn != NULL) + *tzn = tzname[(tm->tm_isdst > 0)]; +#else +#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined +#endif +#else /* !USE_POSIX_TIME */ + *tzp = CTimeZone; /* V7 conventions; don't know timezone? */ + if (tzn != NULL) + *tzn = CTZName; +#endif + + /* otherwise, outside of timezone range so convert to GMT... */ + } + else + { + *tzp = 0; + tm->tm_isdst = 0; + if (tzn != NULL) + *tzn = NULL; + } - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ + return 0; +} /* date2tm() */ - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; +/***************************************************************************** + * Time ADT + *****************************************************************************/ - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); - - return (t11 - t10) < (t21 - t20); -} /* intervallt() */ - -/* - * intervalle - returns TRUE, iff interval i1 is less than or equal to interval i2 - * Check length of intervals. - */ -bool -intervalle(TimeInterval i1, TimeInterval i2) + +TimeADT * +time_in(char *str) { - AbsoluteTime t10, - t11, - t20, - t21; + TimeADT *time; - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ + double fsec; + struct tm tt, + *tm = &tt; - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + int nf; + char lowstr[MAXDATELEN + 1]; + char *field[MAXDATEFIELDS]; + int dtype; + int ftype[MAXDATEFIELDS]; - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) time external representation"); - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); - - return (t11 - t10) <= (t21 - t20); -} /* intervalle() */ - -/* - * intervalgt - returns TRUE, iff interval i1 is less than interval i2 - * Check length of intervals. - */ -bool -intervalgt(TimeInterval i1, TimeInterval i2) -{ - AbsoluteTime t10, - t11, - t20, - t21; + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec) != 0)) + elog(ERROR, "Bad time external representation '%s'", str); - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ + time = palloc(sizeof(TimeADT)); - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + *time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec); - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; + return time; +} /* time_in() */ - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); - - return (t11 - t10) > (t21 - t20); -} /* intervalgt() */ - -/* - * intervalge - returns TRUE, iff interval i1 is less than or equal to interval i2 - * Check length of intervals. - */ -bool -intervalge(TimeInterval i1, TimeInterval i2) -{ - AbsoluteTime t10, - t11, - t20, - t21; - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return FALSE; /* invalid interval */ +char * +time_out(TimeADT *time) +{ + char *result; + struct tm tt, + *tm = &tt; - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + double fsec; + char buf[MAXDATELEN + 1]; - if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - return FALSE; + if (!PointerIsValid(time)) + return NULL; - if (t10 == CURRENT_ABSTIME) - t10 = GetCurrentTransactionStartTime(); - if (t11 == CURRENT_ABSTIME) - t11 = GetCurrentTransactionStartTime(); - if (t20 == CURRENT_ABSTIME) - t20 = GetCurrentTransactionStartTime(); - if (t21 == CURRENT_ABSTIME) - t21 = GetCurrentTransactionStartTime(); + tm->tm_hour = (*time / (60 * 60)); + tm->tm_min = (((int) (*time / 60)) % 60); + tm->tm_sec = (((int) *time) % 60); - return (t11 - t10) >= (t21 - t20); -} /* intervalge() */ + fsec = 0; + EncodeTimeOnly(tm, fsec, DateStyle, buf); -/* - * intervalleneq - returns 1, iff length of interval i is equal to - * reltime t - */ -bool -intervalleneq(TimeInterval i, RelativeTime t) -{ - RelativeTime rt; + result = palloc(strlen(buf) + 1); - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt == t; -} + strcpy(result, buf); -/* - * intervallenne - returns 1, iff length of interval i is not equal - * to reltime t - */ -bool -intervallenne(TimeInterval i, RelativeTime t) -{ - RelativeTime rt; + return result; +} /* time_out() */ - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt != t; -} -/* - * intervallenlt - returns 1, iff length of interval i is less than - * reltime t - */ bool -intervallenlt(TimeInterval i, RelativeTime t) +time_eq(TimeADT *time1, TimeADT *time2) { - RelativeTime rt; + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt < t; -} + return *time1 == *time2; +} /* time_eq() */ -/* - * intervallengt - returns 1, iff length of interval i is greater than - * reltime t - */ bool -intervallengt(TimeInterval i, RelativeTime t) +time_ne(TimeADT *time1, TimeADT *time2) { - RelativeTime rt; + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt > t; -} + return *time1 != *time2; +} /* time_eq() */ -/* - * intervallenle - returns 1, iff length of interval i is less or equal - * than reltime t - */ bool -intervallenle(TimeInterval i, RelativeTime t) +time_lt(TimeADT *time1, TimeADT *time2) { - RelativeTime rt; + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt <= t; -} + return *time1 < *time2; +} /* time_eq() */ -/* - * intervallenge - returns 1, iff length of interval i is greater or - * equal than reltime t - */ bool -intervallenge(TimeInterval i, RelativeTime t) +time_le(TimeADT *time1, TimeADT *time2) { - RelativeTime rt; + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; - if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) - return 0; - rt = intervalrel(i); - return rt != INVALID_RELTIME && rt >= t; -} + return *time1 <= *time2; +} /* time_eq() */ -/* - * intervalct - returns 1, iff interval i1 contains interval i2 - */ bool -intervalct(TimeInterval i1, TimeInterval i2) +time_gt(TimeADT *time1, TimeADT *time2) { - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return 0; - return (abstimele(i1->data[0], i2->data[0]) && - abstimege(i1->data[1], i2->data[1])); -} + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; + + return *time1 > *time2; +} /* time_eq() */ -/* - * intervalov - returns 1, iff interval i1 (partially) overlaps i2 - */ bool -intervalov(TimeInterval i1, TimeInterval i2) +time_ge(TimeADT *time1, TimeADT *time2) { - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - return 0; - return (!(abstimelt(i1->data[1], i2->data[0]) || - abstimegt(i1->data[0], i2->data[1]))); -} + if (!PointerIsValid(time1) || !PointerIsValid(time2)) + return FALSE; -/* - * intervalstart - returns the start of interval i - */ -AbsoluteTime -intervalstart(TimeInterval i) -{ - if (i->status == T_INTERVAL_INVAL) - return INVALID_ABSTIME; - return i->data[0]; -} + return *time1 >= *time2; +} /* time_eq() */ -/* - * intervalend - returns the end of interval i - */ -AbsoluteTime -intervalend(TimeInterval i) +int +time_cmp(TimeADT *time1, TimeADT *time2) { - if (i->status == T_INTERVAL_INVAL) - return INVALID_ABSTIME; - return i->data[1]; -} + return (*time1 < *time2) ? -1 : (((*time1 > *time2) ? 1 : 0)); +} /* time_cmp() */ -/***************************************************************************** - * PRIVATE ROUTINES * - *****************************************************************************/ - -#ifdef NOT_USED -/* - * isreltime - returns 1, iff datestring is of type reltime - * 2, iff datestring is 'invalid time' identifier - * 0, iff datestring contains a syntax error - * VALID time less or equal +/- `@ 68 years' - * +/* timestamp_time() + * Convert timestamp to time data type. */ -int -isreltime(char *str) +TimeADT * +timestamp_time(Timestamp *timestamp) { + TimeADT *result; struct tm tt, *tm = &tt; + int tz; double fsec; - int dtype; - char *field[MAXDATEFIELDS]; - int nf, - ftype[MAXDATEFIELDS]; - char lowstr[MAXDATELEN + 1]; + char *tzn; - if (!PointerIsValid(str)) - return 0; - - if (strlen(str) > MAXDATELEN) - return 0; + if (!PointerIsValid(timestamp)) + elog(ERROR, "Unable to convert null timestamp to date"); - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) - return 0; + if (TIMESTAMP_NOT_FINITE(*timestamp)) + elog(ERROR, "Unable to convert timestamp to date"); - switch (dtype) + if (TIMESTAMP_IS_EPOCH(*timestamp)) { - case (DTK_DELTA): - return (abs(tm->tm_year) <= 68) ? 1 : 0; - break; - - case (DTK_INVALID): - return 2; - break; - - default: - return 0; - break; - } + timestamp2tm(SetTimestamp(*timestamp), NULL, tm, &fsec, NULL); - return 0; -} /* isreltime() */ - -#endif - -#ifdef NOT_USED -int -dummyfunc() -{ - char *p; - char c; - int i; - char unit[UNITMAXLEN]; - char direction[DIRMAXLEN]; - int localSign; - int localUnitNumber; - long localQuantity; - - if (!PointerIsValid(sign)) - sign = &localSign; - - if (!PointerIsValid(unitnr)) - unitnr = &localUnitNumber; - - if (!PointerIsValid(quantity)) - quantity = &localQuantity; - - unit[0] = '\0'; - direction[0] = '\0'; - p = timestring; - /* skip leading blanks */ - while ((c = *p) != '\0') - { - if (c != ' ') - break; - p++; } - - /* Test whether 'invalid time' identifier or not */ - if (!strncmp(INVALID_RELTIME_STR, p, strlen(INVALID_RELTIME_STR) + 1)) - return 2; /* correct 'invalid time' identifier found */ - - /* handle label of relative time */ - if (c != RELTIME_LABEL) - return 0; /* syntax error */ - c = *++p; - if (c != ' ') - return 0; /* syntax error */ - p++; - /* handle the quantity */ - *quantity = 0; - for (;;) + else if (TIMESTAMP_IS_CURRENT(*timestamp)) { - c = *p; - if (isdigit(c)) - { - *quantity = *quantity * 10 + (c - '0'); - p++; - } - else - { - if (c == ' ') - break; /* correct quantity found */ - else - return 0; /* syntax error */ - } - } + timestamp2tm(SetTimestamp(*timestamp), &tz, tm, &fsec, &tzn); - /* handle unit */ - p++; - i = 0; - for (;;) - { - c = *p; - if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1)) - { - unit[i] = c; - p++; - i++; - } - else - { - if ((c == ' ' || c == '\0') - && correct_unit(unit, unitnr)) - break; /* correct unit found */ - else - return 0; /* syntax error */ - } } - - /* handle optional direction */ - if (c == ' ') - p++; - i = 0; - *sign = 1; - for (;;) + else { - c = *p; - if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1)) - { - direction[i] = c; - p++; - i++; - } - else - { - if ((c == ' ' || c == '\0') && i == 0) - { - *sign = 1; - break; /* no direction specified */ - } - if ((c == ' ' || c == '\0') && i != 0) - { - direction[i] = '\0'; - correct_dir(direction, sign); - break; /* correct direction found */ - } - else - return 0; /* syntax error */ - } + if (timestamp2tm(*timestamp, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to convert timestamp to date"); } - return 1; -} + result = palloc(sizeof(TimeADT)); -/* - * correct_unit - returns 1, iff unit is a correct unit description - * - * output parameter: - * unptr: points to an integer which is the appropriate unit number - * (see function isreltime()) - */ -static int -correct_unit(char *unit, int *unptr) -{ - int j = 0; - - while (j < NUNITS) - { - if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0) - { - *unptr = j; - return 1; - } - j++; - } - return 0; /* invalid unit descriptor */ -} + *result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec); -/* - * correct_dir - returns 1, iff direction is a correct identifier - * - * output parameter: - * signptr: points to -1 if dir corresponds to past tense - * else to 1 - */ -static int -correct_dir(char *direction, int *signptr) -{ - *signptr = 1; - if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST) + 1) == 0) - { - *signptr = -1; - return 1; - } - else - return 0; /* invalid direction descriptor */ -} + return result; +} /* timestamp_time() */ -#endif -/* - * istinterval - returns 1, iff i_string is a valid interval descr. - * 0, iff i_string is NOT a valid interval desc. - * 2, iff any time is INVALID_ABSTIME - * - * output parameter: - * i_start, i_end: interval margins - * - * Time interval: - * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]' - * - * OR `Undefined Range' (see also INVALID_INTERVAL_STR) - * - * where <AbsTime> satisfies the syntax of absolute time. - * - * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970'] +/* datetime_timestamp() + * Convert date and time to timestamp data type. */ -static int -istinterval(char *i_string, - AbsoluteTime *i_start, - AbsoluteTime *i_end) +Timestamp * +datetime_timestamp(DateADT date, TimeADT *time) { - char *p, - *p1; - char c; + Timestamp *result; - p = i_string; - /* skip leading blanks up to '[' */ - while ((c = *p) != '\0') + if (!PointerIsValid(time)) { - if (IsSpace(c)) - p++; - else if (c != '[') - return 0; /* syntax error */ - else - break; + result = palloc(sizeof(Timestamp)); + TIMESTAMP_INVALID(*result); } - p++; - /* skip leading blanks up to "'" */ - while ((c = *p) != '\0') - { - if (IsSpace(c)) - p++; - else if (c != '"') - return 0; /* syntax error */ - else - break; - } - p++; - if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0) - return 0; /* undefined range, handled like a syntax - * err. */ - /* search for the end of the first date and change it to a NULL */ - p1 = p; - while ((c = *p1) != '\0') - { - if (c == '"') - { - *p1 = '\0'; - break; - } - p1++; - } - /* get the first date */ - *i_start = nabstimein(p); /* first absolute date */ - /* rechange NULL at the end of the first date to a "'" */ - *p1 = '"'; - p = ++p1; - /* skip blanks up to "'", beginning of second date */ - while ((c = *p) != '\0') - { - if (IsSpace(c)) - p++; - else if (c != '"') - return 0; /* syntax error */ - else - break; - } - p++; - /* search for the end of the second date and change it to a NULL */ - p1 = p; - while ((c = *p1) != '\0') - { - if (c == '"') - { - *p1 = '\0'; - break; - } - p1++; - } - /* get the second date */ - *i_end = nabstimein(p); /* second absolute date */ - /* rechange NULL at the end of the first date to a ''' */ - *p1 = '"'; - p = ++p1; - /* skip blanks up to ']' */ - while ((c = *p) != '\0') + else { - if (IsSpace(c)) - p++; - else if (c != ']') - return 0; /* syntax error */ - else - break; + result = date_timestamp(date); + *result += *time; } - p++; - c = *p; - if (c != '\0') - return 0; /* syntax error */ - /* it seems to be a valid interval */ - return 1; -} - -/***************************************************************************** - * - *****************************************************************************/ - -/* - * timeofday - - * returns the current time as a text. similar to timenow() but returns - * seconds with more precision (up to microsecs). (I need this to compare - * the Wisconsin benchmark with Illustra whose TimeNow() shows current - * time with precision up to microsecs.) - ay 3/95 - */ -text * -timeofday(void) -{ - - struct timeval tp; - struct timezone tpz; - char templ[500]; - char buf[500]; - text *tm; - int len = 0; - - gettimeofday(&tp, &tpz); - strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z", - localtime((time_t *) &tp.tv_sec)); - sprintf(buf, templ, tp.tv_usec); - - len = VARHDRSZ + strlen(buf); - tm = (text *) palloc(len); - VARSIZE(tm) = len; - strncpy(VARDATA(tm), buf, strlen(buf)); - return tm; -} + return result; +} /* datetime_timestamp() */ |