diff options
author | Thomas G. Lockhart <lockhart@fourpalms.org> | 2000-02-16 18:17:02 +0000 |
---|---|---|
committer | Thomas G. Lockhart <lockhart@fourpalms.org> | 2000-02-16 18:17:02 +0000 |
commit | bf566b202ec879d54e411627fb96d5e620d3c246 (patch) | |
tree | 0a88eeeac721c43b5412c6be56343f2852210a54 /src/backend/utils/adt/date.c | |
parent | 8997675c4b962b19029076bd1c023f9bb70a9abf (diff) | |
download | postgresql-bf566b202ec879d54e411627fb96d5e620d3c246.tar.gz postgresql-bf566b202ec879d54e411627fb96d5e620d3c246.zip |
All regression tests pass except for rules.sql (unrelated).
Implement "date/time grand unification".
Transform datetime and timespan into timestamp and interval.
Deprecate datetime and timespan, though translate to new types in gram.y.
Transform all datetime and timespan catalog entries into new types.
Make "INTERVAL" reserved word allowed as a column identifier in gram.y.
Remove dt.h, dt.c files, and retarget datetime.h, datetime.c as utility
routines for all date/time types.
date.{h,c} now deals with date, time types.
timestamp.{h,c} now deals with timestamp, interval types.
nabstime.{h,c} now deals with abstime, reltime, tinterval types.
Make NUMERIC a known native type for purposes of type coersion. Not tested.
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() */ |