From 41f1f5b76ad8e177a2b19116cbf41384f93f3851 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Wed, 16 Feb 2000 17:26:26 +0000 Subject: [PATCH] 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. --- src/backend/parser/gram.y | 9 +- src/backend/parser/parse_coerce.c | 25 +- src/backend/utils/adt/Makefile | 4 +- src/backend/utils/adt/dt.c | 4270 ---------------------------- src/backend/utils/adt/formatting.c | 97 +- src/backend/utils/adt/nabstime.c | 1328 ++++++++- src/backend/utils/adt/timestamp.c | 2220 ++++++++++++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_aggregate.h | 14 +- src/include/catalog/pg_opclass.h | 6 +- src/include/catalog/pg_operator.h | 85 +- src/include/catalog/pg_proc.h | 306 +- src/include/catalog/pg_type.h | 17 +- src/include/parser/parse_coerce.h | 25 +- src/include/utils/builtins.h | 98 +- src/include/utils/date.h | 52 + src/include/utils/datetime.h | 425 ++- src/include/utils/dt.h | 378 --- src/include/utils/formatting.h | 22 +- src/include/utils/nabstime.h | 49 +- src/include/utils/timestamp.h | 208 ++ 21 files changed, 4471 insertions(+), 5171 deletions(-) delete mode 100644 src/backend/utils/adt/dt.c create mode 100644 src/include/utils/date.h delete mode 100644 src/include/utils/dt.h create mode 100644 src/include/utils/timestamp.h diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0da02fd896..4babad9524 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.142 2000/02/15 03:26:38 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.143 2000/02/16 17:24:36 thomas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -5180,6 +5180,7 @@ ColId: IDENT { $$ = $1; } | INITIALLY { $$ = "initially"; } | INSENSITIVE { $$ = "insensitive"; } | INSTEAD { $$ = "instead"; } + | INTERVAL { $$ = "interval"; } | ISNULL { $$ = "isnull"; } | ISOLATION { $$ = "isolation"; } | KEY { $$ = "key"; } @@ -5456,8 +5457,10 @@ xlateSqlType(char *name) return "numeric"; else if (!strcasecmp(name, "char")) return "bpchar"; - else if (!strcasecmp(name, "interval")) - return "timespan"; + else if (!strcasecmp(name, "datetime")) + return "timestamp"; + else if (!strcasecmp(name, "timespan")) + return "interval"; else if (!strcasecmp(name, "boolean")) return "bool"; else diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 67a3413238..7fa7b01688 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.29 2000/01/26 05:56:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.30 2000/02/16 17:24:37 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -293,18 +293,18 @@ TypeCategory(Oid inType) case (INT8OID): case (FLOAT4OID): case (FLOAT8OID): + case (NUMERICOID): case (CASHOID): result = NUMERIC_TYPE; break; case (ABSTIMEOID): case (TIMESTAMPOID): - case (DATETIMEOID): result = DATETIME_TYPE; break; case (RELTIMEOID): - case (TIMESPANOID): + case (INTERVALOID): result = TIMESPAN_TYPE; break; @@ -362,16 +362,18 @@ PreferredType(CATEGORY category, Oid type) case (NUMERIC_TYPE): if (type == OIDOID) result = OIDOID; + else if (type == NUMERICOID) + result = NUMERICOID; else result = FLOAT8OID; break; case (DATETIME_TYPE): - result = DATETIMEOID; + result = TIMESTAMPOID; break; case (TIMESPAN_TYPE): - result = TIMESPANOID; + result = INTERVALOID; break; case (NETWORK_TYPE): @@ -419,22 +421,25 @@ PromoteTypeToNext(Oid inType) result = FLOAT8OID; break; + case (NUMERICOID): + result = NUMERICOID; + break; + case (DATEOID): case (ABSTIMEOID): - case (TIMESTAMPOID): - result = DATETIMEOID; + result = TIMESTAMPOID; break; case (TIMEOID): case (RELTIMEOID): - result = TIMESPANOID; + result = INTERVALOID; break; case (BOOLOID): case (TEXTOID): case (FLOAT8OID): - case (DATETIMEOID): - case (TIMESPANOID): + case (TIMESTAMPOID): + case (INTERVALOID): default: result = inType; break; diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 192928db09..030ca95178 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -4,7 +4,7 @@ # Makefile for utils/adt # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.33 2000/01/25 23:53:51 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.34 2000/02/16 17:24:46 thomas Exp $ # #------------------------------------------------------------------------- @@ -24,7 +24,7 @@ endif endif OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o chunk.o \ - date.o datetime.o datum.o dt.o filename.o float.o \ + date.o datetime.o datum.o filename.o float.o \ geo_ops.o geo_selfuncs.o int.o int8.o like.o \ misc.o nabstime.o name.o not_in.o numeric.o numutils.o \ oid.o oracle_compat.o \ diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c deleted file mode 100644 index 90a5c5c9db..0000000000 --- a/src/backend/utils/adt/dt.c +++ /dev/null @@ -1,4270 +0,0 @@ -/*------------------------------------------------------------------------- - * - * dt.c - * Functions for the built-in type "dt". - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.83 2000/02/15 03:17:09 thomas Exp $ - * - *------------------------------------------------------------------------- - */ -#include -#include -#include -#include - -#include "postgres.h" -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifndef USE_POSIX_TIME -#include -#endif - -#include "miscadmin.h" -#include "utils/builtins.h" - -static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); -static int DecodeNumber(int flen, char *field, - int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); -static int DecodeNumberField(int len, char *str, - int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); -static int DecodeSpecial(int field, char *lowtoken, int *val); -static int DecodeTime(char *str, int fmask, int *tmask, - struct tm * tm, double *fsec); -static int DecodeTimezone(char *str, int *tzp); -static int DecodeUnits(int field, char *lowtoken, int *val); -static int EncodeSpecialDateTime(DateTime dt, char *str); -static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); -static DateTime dt2local(DateTime dt, int timezone); -static void dt2time(DateTime dt, int *hour, int *min, double *sec); -static int j2day(int jd); -static double time2t(const int hour, const int min, const double sec); -static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec); -static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span); - - -#define USE_DATE_CACHE 1 -#define ROUND_ALL 0 - -int day_tab[2][13] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, -{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}; - - -char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", -"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; - -char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", -"Thursday", "Friday", "Saturday", NULL}; - -/* TMODULO() - * Macro to replace modf(), which is broken on some platforms. - */ -#define TMODULO(t,q,u) \ -do { \ - q = ((t < 0)? ceil(t / u): floor(t / u)); \ - if (q != 0) \ - t -= rint(q * u); \ -} while(0) - -static void GetEpochTime(struct tm * tm); - -#define UTIME_MINYEAR (1901) -#define UTIME_MINMONTH (12) -#define UTIME_MINDAY (14) -#define UTIME_MAXYEAR (2038) -#define UTIME_MAXMONTH (01) -#define UTIME_MAXDAY (18) - -#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ - || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ - || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ - && ((y < UTIME_MAXYEAR) \ - || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ - || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) - - -/***************************************************************************** - * USER I/O ROUTINES * - *****************************************************************************/ - -/* datetime_in() - * Convert a string to internal form. - */ -DateTime * -datetime_in(char *str) -{ - DateTime *result; - - double fsec; - struct tm tt, - *tm = &tt; - int tz; - int dtype; - int nf; - char *field[MAXDATEFIELDS]; - int ftype[MAXDATEFIELDS]; - char lowstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) datetime external representation"); - - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) - elog(ERROR, "Bad datetime external representation '%s'", str); - - result = palloc(sizeof(DateTime)); - - switch (dtype) - { - case DTK_DATE: - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "Datetime out of range '%s'", str); - break; - - case DTK_EPOCH: - DATETIME_EPOCH(*result); - break; - - case DTK_CURRENT: - DATETIME_CURRENT(*result); - break; - - case DTK_LATE: - DATETIME_NOEND(*result); - break; - - case DTK_EARLY: - DATETIME_NOBEGIN(*result); - break; - - case DTK_INVALID: - DATETIME_INVALID(*result); - break; - - default: - elog(ERROR, "Internal coding error, can't input datetime '%s'", str); - } - - return result; -} /* datetime_in() */ - -/* datetime_out() - * Convert a datetime to external form. - */ -char * -datetime_out(DateTime *dt) -{ - char *result; - int tz; - struct tm tt, - *tm = &tt; - double fsec; - char *tzn; - char buf[MAXDATELEN + 1]; - - if (!PointerIsValid(dt)) - return NULL; - - if (DATETIME_IS_RESERVED(*dt)) - { - EncodeSpecialDateTime(*dt, buf); - - } - else if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) == 0) - { - EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); - - } - else - EncodeSpecialDateTime(DT_INVALID, buf); - - result = palloc(strlen(buf) + 1); - - strcpy(result, buf); - - return result; -} /* datetime_out() */ - - -/* timespan_in() - * Convert a string to internal form. - * - * External format(s): - * Uses the generic date/time parsing and decoding routines. - */ -TimeSpan * -timespan_in(char *str) -{ - TimeSpan *span; - - double fsec; - struct tm tt, - *tm = &tt; - int dtype; - int nf; - char *field[MAXDATEFIELDS]; - int ftype[MAXDATEFIELDS]; - char lowstr[MAXDATELEN + 1]; - - tm->tm_year = 0; - tm->tm_mon = 0; - tm->tm_mday = 0; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - fsec = 0; - - if (!PointerIsValid(str)) - elog(ERROR, "Bad (null) timespan external representation"); - - if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) - || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) - elog(ERROR, "Bad timespan external representation '%s'", str); - - span = palloc(sizeof(TimeSpan)); - - switch (dtype) - { - case DTK_DELTA: - if (tm2timespan(tm, fsec, span) != 0) - { -#if NOT_USED - TIMESPAN_INVALID(span); -#endif - elog(ERROR, "Bad timespan external representation '%s'", str); - } - break; - - default: - elog(ERROR, "Internal coding error, can't input timespan '%s'", str); - } - - return span; -} /* timespan_in() */ - -/* timespan_out() - * Convert a time span to external form. - */ -char * -timespan_out(TimeSpan *span) -{ - char *result; - - struct tm tt, - *tm = &tt; - double fsec; - char buf[MAXDATELEN + 1]; - - if (!PointerIsValid(span)) - return NULL; - - if (timespan2tm(*span, tm, &fsec) != 0) - return NULL; - - if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0) - elog(ERROR, "Unable to format timespan"); - - result = palloc(strlen(buf) + 1); - - strcpy(result, buf); - return result; -} /* timespan_out() */ - - -/***************************************************************************** - * PUBLIC ROUTINES * - *****************************************************************************/ - - -bool -datetime_finite(DateTime *datetime) -{ - if (!PointerIsValid(datetime)) - return FALSE; - - return !DATETIME_NOT_FINITE(*datetime); -} /* datetime_finite() */ - -bool -timespan_finite(TimeSpan *timespan) -{ - if (!PointerIsValid(timespan)) - return FALSE; - - return !TIMESPAN_NOT_FINITE(*timespan); -} /* timespan_finite() */ - - -/*---------------------------------------------------------- - * Relational operators for datetime. - *---------------------------------------------------------*/ - -static void -GetEpochTime(struct tm * tm) -{ - struct tm *t0; - time_t epoch = 0; - - t0 = gmtime(&epoch); - - tm->tm_year = t0->tm_year; - tm->tm_mon = t0->tm_mon; - tm->tm_mday = t0->tm_mday; - tm->tm_hour = t0->tm_hour; - tm->tm_min = t0->tm_min; - tm->tm_sec = t0->tm_sec; - - if (tm->tm_year < 1900) - tm->tm_year += 1900; - tm->tm_mon++; - - return; -} /* GetEpochTime() */ - -DateTime -SetDateTime(DateTime dt) -{ - struct tm tt; - - if (DATETIME_IS_CURRENT(dt)) - { - GetCurrentTime(&tt); - tm2datetime(&tt, 0, NULL, &dt); - dt = dt2local(dt, -CTimeZone); - } - else - { /* if (DATETIME_IS_EPOCH(dt1)) */ - GetEpochTime(&tt); - tm2datetime(&tt, 0, NULL, &dt); - } - - return dt; -} /* SetDateTime() */ - -/* datetime_relop - is datetime1 relop datetime2 - */ -bool -datetime_eq(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 == dt2; -} /* datetime_eq() */ - -bool -datetime_ne(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 != dt2; -} /* datetime_ne() */ - -bool -datetime_lt(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 < dt2; -} /* datetime_lt() */ - -bool -datetime_gt(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 > dt2; -} /* datetime_gt() */ - -bool -datetime_le(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 <= dt2; -} /* datetime_le() */ - -bool -datetime_ge(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return FALSE; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2)) - return FALSE; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - return dt1 >= dt2; -} /* datetime_ge() */ - - -/* datetime_cmp - 3-state comparison for datetime - * collate invalid datetime at the end - */ -int -datetime_cmp(DateTime *datetime1, DateTime *datetime2) -{ - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return 0; - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_INVALID(dt1)) - { - return (DATETIME_IS_INVALID(dt2) ? 0 : 1); - - } - else if (DATETIME_IS_INVALID(dt2)) - { - return -1; - - } - else - { - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - } - - return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0)); -} /* datetime_cmp() */ - - -/* timespan_relop - is timespan1 relop timespan2 - */ -bool -timespan_eq(TimeSpan *timespan1, TimeSpan *timespan2) -{ - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - return ((timespan1->time == timespan2->time) - && (timespan1->month == timespan2->month)); -} /* timespan_eq() */ - -bool -timespan_ne(TimeSpan *timespan1, TimeSpan *timespan2) -{ - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - return ((timespan1->time != timespan2->time) - || (timespan1->month != timespan2->month)); -} /* timespan_ne() */ - -bool -timespan_lt(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 < span2; -} /* timespan_lt() */ - -bool -timespan_gt(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 > span2; -} /* timespan_gt() */ - -bool -timespan_le(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 <= span2; -} /* timespan_le() */ - -bool -timespan_ge(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return FALSE; - - if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2)) - return FALSE; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return span1 >= span2; -} /* timespan_ge() */ - - -/* timespan_cmp - 3-state comparison for timespan - */ -int -timespan_cmp(TimeSpan *timespan1, TimeSpan *timespan2) -{ - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return 0; - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - return TIMESPAN_IS_INVALID(*timespan2) ? 0 : 1; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - return -1; - - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - return (span1 < span2) ? -1 : (span1 > span2) ? 1 : 0; -} /* timespan_cmp() */ - - -/*---------------------------------------------------------- - * "Arithmetic" operators on date/times. - * datetime_foo returns foo as an object (pointer) that - * can be passed between languages. - * datetime_xx is an internal routine which returns the - * actual value. - *---------------------------------------------------------*/ - -DateTime * -datetime_smaller(DateTime *datetime1, DateTime *datetime2) -{ - DateTime *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1)) - *result = dt2; - else if (DATETIME_IS_INVALID(dt2)) - *result = dt1; - else - *result = ((dt2 < dt1) ? dt2 : dt1); - - return result; -} /* datetime_smaller() */ - -DateTime * -datetime_larger(DateTime *datetime1, DateTime *datetime2) -{ - DateTime *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1)) - *result = dt2; - else if (DATETIME_IS_INVALID(dt2)) - *result = dt1; - else - *result = ((dt2 > dt1) ? dt2 : dt1); - - return result; -} /* datetime_larger() */ - - -TimeSpan * -datetime_mi(DateTime *datetime1, DateTime *datetime2) -{ - TimeSpan *result; - - DateTime dt1, - dt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - dt1 = *datetime1; - dt2 = *datetime2; - - result = palloc(sizeof(TimeSpan)); - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1) - || DATETIME_IS_INVALID(dt2)) - { - DATETIME_INVALID(result->time); - - } - else - result->time = JROUND(dt1 - dt2); - result->month = 0; - - return result; -} /* datetime_mi() */ - - -/* datetime_pl_span() - * Add a timespan to a datetime data type. - * Note that timespan has provisions for qualitative year/month - * units, so try to do the right thing with them. - * To add a month, increment the month, and use the same day of month. - * Then, if the next month has fewer days, set the day of month - * to the last day of month. - * Lastly, add in the "quantitative time". - */ -DateTime * -datetime_pl_span(DateTime *datetime, TimeSpan *span) -{ - DateTime *result; - DateTime dt; - int tz; - char *tzn; - - if ((!PointerIsValid(datetime)) || (!PointerIsValid(span))) - return NULL; - - result = palloc(sizeof(DateTime)); - - if (DATETIME_NOT_FINITE(*datetime)) - { - *result = *datetime; - - } - else if (TIMESPAN_IS_INVALID(*span)) - { - DATETIME_INVALID(*result); - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if (span->month != 0) - { - struct tm tt, - *tm = &tt; - double fsec; - - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0) - { - tm->tm_mon += span->month; - if (tm->tm_mon > 12) - { - tm->tm_year += ((tm->tm_mon - 1) / 12); - tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); - } - else if (tm->tm_mon < 1) - { - tm->tm_year += ((tm->tm_mon / 12) - 1); - tm->tm_mon = ((tm->tm_mon % 12) + 12); - } - - /* adjust for end of month boundary problems... */ - if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) - tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); - - if (tm2datetime(tm, fsec, &tz, &dt) != 0) - elog(ERROR, "Unable to add datetime and timespan"); - - } - else - DATETIME_INVALID(dt); - } - -#ifdef ROUND_ALL - dt = JROUND(dt + span->time); -#else - dt += span->time; -#endif - - *result = dt; - } - - return result; -} /* datetime_pl_span() */ - -DateTime * -datetime_mi_span(DateTime *datetime, TimeSpan *span) -{ - DateTime *result; - TimeSpan tspan; - - if (!PointerIsValid(datetime) || !PointerIsValid(span)) - return NULL; - - tspan.month = -span->month; - tspan.time = -span->time; - - result = datetime_pl_span(datetime, &tspan); - - return result; -} /* datetime_mi_span() */ - - -TimeSpan * -timespan_um(TimeSpan *timespan) -{ - TimeSpan *result; - - if (!PointerIsValid(timespan)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->time = -(timespan->time); - result->month = -(timespan->month); - - return result; -} /* timespan_um() */ - - -TimeSpan * -timespan_smaller(TimeSpan *timespan1, TimeSpan *timespan2) -{ - TimeSpan *result; - - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - { - result->time = timespan1->time; - result->month = timespan1->month; - - } - else - { - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - if (span2 < span1) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else - { - result->time = timespan1->time; - result->month = timespan1->month; - } - } - - return result; -} /* timespan_smaller() */ - -TimeSpan * -timespan_larger(TimeSpan *timespan1, TimeSpan *timespan2) -{ - TimeSpan *result; - - double span1, - span2; - - if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - if (TIMESPAN_IS_INVALID(*timespan1)) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else if (TIMESPAN_IS_INVALID(*timespan2)) - { - result->time = timespan1->time; - result->month = timespan1->month; - - } - else - { - span1 = timespan1->time; - if (timespan1->month != 0) - span1 += (timespan1->month * (30.0 * 86400)); - span2 = timespan2->time; - if (timespan2->month != 0) - span2 += (timespan2->month * (30.0 * 86400)); - - if (span2 > span1) - { - result->time = timespan2->time; - result->month = timespan2->month; - - } - else - { - result->time = timespan1->time; - result->month = timespan1->month; - } - } - - return result; -} /* timespan_larger() */ - - -TimeSpan * -timespan_pl(TimeSpan *span1, TimeSpan *span2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->month = (span1->month + span2->month); - result->time = JROUND(span1->time + span2->time); - - return result; -} /* timespan_pl() */ - -TimeSpan * -timespan_mi(TimeSpan *span1, TimeSpan *span2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - result->month = (span1->month - span2->month); - result->time = JROUND(span1->time - span2->time); - - return result; -} /* timespan_mi() */ - -TimeSpan * -timespan_div(TimeSpan *span1, float8 *arg2) -{ - TimeSpan *result; - - if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2))) - return NULL; - - if (!PointerIsValid(result = palloc(sizeof(TimeSpan)))) - elog(ERROR, "Memory allocation failed, can't divide timespans"); - - if (*arg2 == 0.0) - elog(ERROR, "timespan_div: divide by 0.0 error"); - - result->month = rint(span1->month / *arg2); - result->time = JROUND(span1->time / *arg2); - - return result; -} /* timespan_div() */ - -/* datetime_age() - * Calculate time difference while retaining year/month fields. - * Note that this does not result in an accurate absolute time span - * since year and month are out of context once the arithmetic - * is done. - */ -TimeSpan * -datetime_age(DateTime *datetime1, DateTime *datetime2) -{ - TimeSpan *result; - - DateTime dt1, - dt2; - double fsec, - fsec1, - fsec2; - struct tm tt, - *tm = &tt; - struct tm tt1, - *tm1 = &tt1; - struct tm tt2, - *tm2 = &tt2; - - if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2)) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - dt1 = *datetime1; - dt2 = *datetime2; - - if (DATETIME_IS_RELATIVE(dt1)) - dt1 = SetDateTime(dt1); - if (DATETIME_IS_RELATIVE(dt2)) - dt2 = SetDateTime(dt2); - - if (DATETIME_IS_INVALID(dt1) - || DATETIME_IS_INVALID(dt2)) - { - DATETIME_INVALID(result->time); - - } - else if ((datetime2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) - && (datetime2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) - { - fsec = (fsec1 - fsec2); - tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); - tm->tm_min = (tm1->tm_min - tm2->tm_min); - tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); - tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); - tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); - tm->tm_year = (tm1->tm_year - tm2->tm_year); - - /* flip sign if necessary... */ - if (dt1 < dt2) - { - fsec = -fsec; - tm->tm_sec = -tm->tm_sec; - tm->tm_min = -tm->tm_min; - tm->tm_hour = -tm->tm_hour; - tm->tm_mday = -tm->tm_mday; - tm->tm_mon = -tm->tm_mon; - tm->tm_year = -tm->tm_year; - } - - if (tm->tm_sec < 0) - { - tm->tm_sec += 60; - tm->tm_min--; - } - - if (tm->tm_min < 0) - { - tm->tm_min += 60; - tm->tm_hour--; - } - - if (tm->tm_hour < 0) - { - tm->tm_hour += 24; - tm->tm_mday--; - } - - if (tm->tm_mday < 0) - { - if (dt1 < dt2) - { - tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1]; - tm->tm_mon--; - } - else - { - tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1]; - tm->tm_mon--; - } - } - - if (tm->tm_mon < 0) - { - tm->tm_mon += 12; - tm->tm_year--; - } - - /* recover sign if necessary... */ - if (dt1 < dt2) - { - fsec = -fsec; - tm->tm_sec = -tm->tm_sec; - tm->tm_min = -tm->tm_min; - tm->tm_hour = -tm->tm_hour; - tm->tm_mday = -tm->tm_mday; - tm->tm_mon = -tm->tm_mon; - tm->tm_year = -tm->tm_year; - } - - if (tm2timespan(tm, fsec, result) != 0) - elog(ERROR, "Unable to decode datetime"); - - } - else - elog(ERROR, "Unable to decode datetime"); - - return result; -} /* datetime_age() */ - - -/*---------------------------------------------------------- - * Conversion operators. - *---------------------------------------------------------*/ - - -/* datetime_text() - * Convert datetime to text data type. - */ -text * -datetime_text(DateTime *datetime) -{ - text *result; - char *str; - int len; - - if (!PointerIsValid(datetime)) - return NULL; - - str = datetime_out(datetime); - - if (!PointerIsValid(str)) - return NULL; - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - return result; -} /* datetime_text() */ - - -/* text_datetime() - * Convert text string to datetime. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -DateTime * -text_datetime(text *str) -{ - DateTime *result; - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - return NULL; - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - result = datetime_in(dstr); - - return result; -} /* text_datetime() */ - - -/* timespan_text() - * Convert timespan to text data type. - */ -text * -timespan_text(TimeSpan *timespan) -{ - text *result; - char *str; - int len; - - if (!PointerIsValid(timespan)) - return NULL; - - str = timespan_out(timespan); - - if (!PointerIsValid(str)) - return NULL; - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - return result; -} /* timespan_text() */ - - -/* text_timespan() - * Convert text string to timespan. - * Text type may not be null terminated, so copy to temporary string - * then call the standard input routine. - */ -TimeSpan * -text_timespan(text *str) -{ - TimeSpan *result; - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (!PointerIsValid(str)) - return NULL; - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - result = timespan_in(dstr); - - return result; -} /* text_timespan() */ - -/* datetime_trunc() - * Extract specified field from datetime. - */ -DateTime * -datetime_trunc(text *units, DateTime *datetime) -{ - DateTime *result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - char *tzn; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(datetime))) - return NULL; - - result = palloc(sizeof(DateTime)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { -#if NOT_USED -/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ - elog(ERROR, "Datetime is not finite", NULL); -#endif - *result = 0; - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)) - { - switch (val) - { - case DTK_MILLENIUM: - tm->tm_year = (tm->tm_year / 1000) * 1000; - case DTK_CENTURY: - tm->tm_year = (tm->tm_year / 100) * 100; - case DTK_DECADE: - tm->tm_year = (tm->tm_year / 10) * 10; - case DTK_YEAR: - tm->tm_mon = 1; - case DTK_QUARTER: - tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1; - case DTK_MONTH: - tm->tm_mday = 1; - case DTK_DAY: - tm->tm_hour = 0; - case DTK_HOUR: - tm->tm_min = 0; - case DTK_MINUTE: - tm->tm_sec = 0; - case DTK_SECOND: - fsec = 0; - break; - - case DTK_MILLISEC: - fsec = rint(fsec * 1000) / 1000; - break; - - case DTK_MICROSEC: - fsec = rint(fsec * 1000000) / 1000000; - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - result = NULL; - } - - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { -#ifdef USE_POSIX_TIME - tm->tm_isdst = -1; - tm->tm_year -= 1900; - tm->tm_mon -= 1; - tm->tm_isdst = -1; - mktime(tm); - tm->tm_year += 1900; - tm->tm_mon += 1; - -#if defined(HAVE_TM_ZONE) - tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ -#elif defined(HAVE_INT_TIMEZONE) - -#ifdef __CYGWIN__ - tz = (tm->tm_isdst ? (_timezone - 3600) : _timezone); -#else - tz = (tm->tm_isdst ? (timezone - 3600) : timezone); -#endif - -#else -#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined -#endif - -#else /* !USE_POSIX_TIME */ - tz = CTimeZone; -#endif - } - else - { - tm->tm_isdst = 0; - tz = 0; - } - - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "Unable to truncate datetime to '%s'", lowunits); - -#if NOT_USED - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - DATETIME_EPOCH(*result); - *result = dt - SetDateTime(*result); -#endif - - } - else - { - elog(ERROR, "Datetime units '%s' not recognized", lowunits); - result = NULL; - } - } - - return result; -} /* datetime_trunc() */ - -/* timespan_trunc() - * Extract specified field from timespan. - */ -TimeSpan * -timespan_trunc(text *units, TimeSpan *timespan) -{ - TimeSpan *result; - - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(timespan))) - return NULL; - - result = palloc(sizeof(TimeSpan)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - - if (TIMESPAN_IS_INVALID(*timespan)) - { -#if NOT_USED - elog(ERROR, "Timespan is not finite", NULL); -#endif - result = NULL; - - } - else if (type == UNITS) - { - - if (timespan2tm(*timespan, tm, &fsec) == 0) - { - switch (val) - { - case DTK_MILLENIUM: - tm->tm_year = (tm->tm_year / 1000) * 1000; - case DTK_CENTURY: - tm->tm_year = (tm->tm_year / 100) * 100; - case DTK_DECADE: - tm->tm_year = (tm->tm_year / 10) * 10; - case DTK_YEAR: - tm->tm_mon = 0; - case DTK_QUARTER: - tm->tm_mon = (3 * (tm->tm_mon / 4)); - case DTK_MONTH: - tm->tm_mday = 0; - case DTK_DAY: - tm->tm_hour = 0; - case DTK_HOUR: - tm->tm_min = 0; - case DTK_MINUTE: - tm->tm_sec = 0; - case DTK_SECOND: - fsec = 0; - break; - - case DTK_MILLISEC: - fsec = rint(fsec * 1000) / 1000; - break; - - case DTK_MICROSEC: - fsec = rint(fsec * 1000000) / 1000000; - break; - - default: - elog(ERROR, "Timespan units '%s' not supported", lowunits); - result = NULL; - } - - if (tm2timespan(tm, fsec, result) != 0) - elog(ERROR, "Unable to truncate timespan to '%s'", lowunits); - - } - else - { - elog(NOTICE, "Timespan out of range"); - result = NULL; - } - -#if NOT_USED - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - *result = timespan->time; - if (timespan->month != 0) - { - *result += ((365.25 * 86400) * (timespan->month / 12)); - *result += ((30 * 86400) * (timespan->month % 12)); - } -#endif - - } - else - { - elog(ERROR, "Timespan units '%s' not recognized", textout(units)); - result = NULL; - } - - return result; -} /* timespan_trunc() */ - - -/* datetime_part() - * Extract specified field from datetime. - */ -float64 -datetime_part(text *units, DateTime *datetime) -{ - float64 result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double dummy; - double fsec; - char *tzn; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(datetime))) - return NULL; - - result = palloc(sizeof(float64data)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - if (type == IGNORE) - type = DecodeSpecial(0, lowunits, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { -#if NOT_USED -/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ - elog(ERROR, "Datetime is not finite", NULL); -#endif - *result = 0; - - } - else - { - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - - if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)) - { - switch (val) - { - case DTK_TZ: - *result = tz; - break; - - case DTK_TZ_MINUTE: - *result = tz / 60; - TMODULO(*result, dummy, 60e0); - break; - - case DTK_TZ_HOUR: - dummy = tz; - TMODULO(dummy, *result, 3600e0); - break; - - case DTK_MICROSEC: - *result = (fsec * 1000000); - break; - - case DTK_MILLISEC: - *result = (fsec * 1000); - break; - - case DTK_SECOND: - *result = (tm->tm_sec + fsec); - break; - - case DTK_MINUTE: - *result = tm->tm_min; - break; - - case DTK_HOUR: - *result = tm->tm_hour; - break; - - case DTK_DAY: - *result = tm->tm_mday; - break; - - case DTK_MONTH: - *result = tm->tm_mon; - break; - - case DTK_QUARTER: - *result = (tm->tm_mon / 4) + 1; - break; - - case DTK_YEAR: - *result = tm->tm_year; - break; - - case DTK_DECADE: - *result = (tm->tm_year / 10); - break; - - case DTK_CENTURY: - *result = (tm->tm_year / 100); - break; - - case DTK_MILLENIUM: - *result = (tm->tm_year / 1000); - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - *result = 0; - } - - } - else if (type == RESERV) - { - switch (val) - { - case DTK_EPOCH: - DATETIME_EPOCH(*result); - *result = dt - SetDateTime(*result); - break; - - case DTK_DOW: - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "Unable to encode datetime"); - - *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); - break; - - case DTK_DOY: - if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "Unable to encode datetime"); - - *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - - date2j(tm->tm_year, 1, 1) + 1); - break; - - default: - elog(ERROR, "Datetime units '%s' not supported", lowunits); - *result = 0; - } - - } - else - { - elog(ERROR, "Datetime units '%s' not recognized", lowunits); - *result = 0; - } - } - - return result; -} /* datetime_part() */ - - -/* timespan_part() - * Extract specified field from timespan. - */ -float64 -timespan_part(text *units, TimeSpan *timespan) -{ - float64 result; - - int type, - val; - int i; - char *up, - *lp, - lowunits[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - - if ((!PointerIsValid(units)) || (!PointerIsValid(timespan))) - return NULL; - - result = palloc(sizeof(float64data)); - - up = VARDATA(units); - lp = lowunits; - for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeUnits(0, lowunits, &val); - if (type == IGNORE) - type = DecodeSpecial(0, lowunits, &val); - - if (TIMESPAN_IS_INVALID(*timespan)) - { -#if NOT_USED - elog(ERROR, "Timespan is not finite"); -#endif - *result = 0; - - } - else if (type == UNITS) - { - - if (timespan2tm(*timespan, tm, &fsec) == 0) - { - switch (val) - { - case DTK_MICROSEC: - *result = (fsec * 1000000); - break; - - case DTK_MILLISEC: - *result = (fsec * 1000); - break; - - case DTK_SECOND: - *result = (tm->tm_sec + fsec); - break; - - case DTK_MINUTE: - *result = tm->tm_min; - break; - - case DTK_HOUR: - *result = tm->tm_hour; - break; - - case DTK_DAY: - *result = tm->tm_mday; - break; - - case DTK_MONTH: - *result = tm->tm_mon; - break; - - case DTK_QUARTER: - *result = (tm->tm_mon / 4) + 1; - break; - - case DTK_YEAR: - *result = tm->tm_year; - break; - - case DTK_DECADE: - *result = (tm->tm_year / 10); - break; - - case DTK_CENTURY: - *result = (tm->tm_year / 100); - break; - - case DTK_MILLENIUM: - *result = (tm->tm_year / 1000); - break; - - default: - elog(ERROR, "Timespan units '%s' not yet supported", textout(units)); - result = NULL; - } - - } - else - { - elog(NOTICE, "Timespan out of range"); - *result = 0; - } - - } - else if ((type == RESERV) && (val == DTK_EPOCH)) - { - *result = timespan->time; - if (timespan->month != 0) - { - *result += ((365.25 * 86400) * (timespan->month / 12)); - *result += ((30 * 86400) * (timespan->month % 12)); - } - - } - else - { - elog(ERROR, "Timespan units '%s' not recognized", textout(units)); - *result = 0; - } - - return result; -} /* timespan_part() */ - - -/* datetime_zone() - * Encode datetime type with specified time zone. - */ -text * -datetime_zone(text *zone, DateTime *datetime) -{ - text *result; - - DateTime dt; - int tz; - int type, - val; - int i; - char *up, - *lp, - lowzone[MAXDATELEN + 1]; - char *tzn, - upzone[MAXDATELEN + 1]; - double fsec; - struct tm tt, - *tm = &tt; - char buf[MAXDATELEN + 1]; - int len; - - if ((!PointerIsValid(zone)) || (!PointerIsValid(datetime))) - return NULL; - - up = VARDATA(zone); - lp = lowzone; - for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++) - *lp++ = tolower(*up++); - *lp = '\0'; - - type = DecodeSpecial(0, lowzone, &val); - - if (DATETIME_NOT_FINITE(*datetime)) - { - - /* - * could return null but Postgres doesn't like that currently. - - * tgl 97/06/12 - */ - elog(ERROR, "Datetime is not finite"); - result = NULL; - - } - else if ((type == TZ) || (type == DTZ)) - { - tm->tm_isdst = ((type == DTZ) ? 1 : 0); - tz = val * 60; - - dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime); - dt = dt2local(dt, tz); - - if (datetime2tm(dt, NULL, tm, &fsec, NULL) != 0) - elog(ERROR, "Datetime not legal"); - - up = upzone; - lp = lowzone; - for (i = 0; *lp != '\0'; i++) - *up++ = toupper(*lp++); - *up = '\0'; - - tzn = upzone; - EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); - - len = (strlen(buf) + VARHDRSZ); - - result = palloc(len); - - VARSIZE(result) = len; - memmove(VARDATA(result), buf, (len - VARHDRSZ)); - - } - else - { - elog(ERROR, "Time zone '%s' not recognized", lowzone); - result = NULL; - } - - return result; -} /* datetime_zone() */ - - -/***************************************************************************** - * PRIVATE ROUTINES * - *****************************************************************************/ - -/* definitions for squeezing values into "value" */ -#define ABS_SIGNBIT (char) 0200 -#define VALMASK (char) 0177 -#define NEG(n) ((n)|ABS_SIGNBIT) -#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c)) -#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */ -#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10)) - -/* - * to keep this table reasonably small, we divide the lexval for TZ and DTZ - * entries by 10 and truncate the text field at MAXTOKLEN characters. - * the text field is not guaranteed to be NULL-terminated. - */ -static datetkn datetktbl[] = { -/* text token lexval */ - {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */ - {"acsst", DTZ, 63}, /* Cent. Australia */ - {"acst", TZ, 57}, /* Cent. Australia */ - {DA_D, ADBC, AD}, /* "ad" for years >= 0 */ - {"abstime", IGNORE, 0}, /* "abstime" for pre-v6.1 "Invalid - * Abstime" */ - {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */ - {"aesst", DTZ, 66}, /* E. Australia */ - {"aest", TZ, 60}, /* Australia Eastern Std Time */ - {"ahst", TZ, NEG(60)}, /* Alaska-Hawaii Std Time */ - {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */ - {"am", AMPM, AM}, - {"apr", MONTH, 4}, - {"april", MONTH, 4}, - {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */ - {"at", IGNORE, 0}, /* "at" (throwaway) */ - {"aug", MONTH, 8}, - {"august", MONTH, 8}, - {"awsst", DTZ, 54}, /* W. Australia */ - {"awst", TZ, 48}, /* W. Australia */ - {DB_C, ADBC, BC}, /* "bc" for years < 0 */ - {"bst", TZ, 6}, /* British Summer Time */ - {"bt", TZ, 18}, /* Baghdad Time */ - {"cadt", DTZ, 63}, /* Central Australian DST */ - {"cast", TZ, 57}, /* Central Australian ST */ - {"cat", TZ, NEG(60)}, /* Central Alaska Time */ - {"cct", TZ, 48}, /* China Coast */ - {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */ - {"cet", TZ, 6}, /* Central European Time */ - {"cetdst", DTZ, 12}, /* Central European Dayl.Time */ -#if USE_AUSTRALIAN_RULES - {"cst", TZ, 63}, /* Australia Eastern Std Time */ -#else - {"cst", TZ, NEG(36)}, /* Central Standard Time */ -#endif - {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */ - {"dec", MONTH, 12}, - {"december", MONTH, 12}, - {"dnt", TZ, 6}, /* Dansk Normal Tid */ - {"dow", RESERV, DTK_DOW}, /* day of week */ - {"doy", RESERV, DTK_DOY}, /* day of year */ - {"dst", DTZMOD, 6}, - {"east", TZ, 60}, /* East Australian Std Time */ - {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */ - {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */ - {"eetdst", DTZ, 18}, /* Eastern Europe */ - {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */ -#if USE_AUSTRALIAN_RULES - {"est", TZ, 60}, /* Australia Eastern Std Time */ -#else - {"est", TZ, NEG(30)}, /* Eastern Standard Time */ -#endif - {"feb", MONTH, 2}, - {"february", MONTH, 2}, - {"fri", DOW, 5}, - {"friday", DOW, 5}, - {"fst", TZ, 6}, /* French Summer Time */ - {"fwt", DTZ, 12}, /* French Winter Time */ - {"gmt", TZ, 0}, /* Greenwish Mean Time */ - {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */ - {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */ - {"hmt", DTZ, 18}, /* Hellas ? ? */ - {"hst", TZ, NEG(60)}, /* Hawaii Std Time */ - {"idle", TZ, 72}, /* Intl. Date Line, East */ - {"idlw", TZ, NEG(72)}, /* Intl. Date Line, West */ - {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */ - {INVALID, RESERV, DTK_INVALID}, - /* "invalid" reserved for invalid time */ - {"ist", TZ, 12}, /* Israel */ - {"it", TZ, 21}, /* Iran Time */ - {"jan", MONTH, 1}, - {"january", MONTH, 1}, - {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */ - {"jt", TZ, 45}, /* Java Time */ - {"jul", MONTH, 7}, - {"july", MONTH, 7}, - {"jun", MONTH, 6}, - {"june", MONTH, 6}, - {"kst", TZ, 54}, /* Korea Standard Time */ - {"ligt", TZ, 60}, /* From Melbourne, Australia */ - {"mar", MONTH, 3}, - {"march", MONTH, 3}, - {"may", MONTH, 5}, - {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */ - {"mest", DTZ, 12}, /* Middle Europe Summer Time */ - {"met", TZ, 6}, /* Middle Europe Time */ - {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */ - {"mewt", TZ, 6}, /* Middle Europe Winter Time */ - {"mez", TZ, 6}, /* Middle Europe Zone */ - {"mon", DOW, 1}, - {"monday", DOW, 1}, - {"mst", TZ, NEG(42)}, /* Mountain Standard Time */ - {"mt", TZ, 51}, /* Moluccas Time */ - {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */ - {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */ - {"nor", TZ, 6}, /* Norway Standard Time */ - {"nov", MONTH, 11}, - {"november", MONTH, 11}, - {NOW, RESERV, DTK_NOW}, /* current transaction time */ - {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */ - {"nt", TZ, NEG(66)}, /* Nome Time */ - {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */ - {"nzst", TZ, 72}, /* New Zealand Standard Time */ - {"nzt", TZ, 72}, /* New Zealand Time */ - {"oct", MONTH, 10}, - {"october", MONTH, 10}, - {"on", IGNORE, 0}, /* "on" (throwaway) */ - {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */ - {"pm", AMPM, PM}, - {"pst", TZ, NEG(48)}, /* Pacific Standard Time */ - {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */ - {"sast", TZ, 57}, /* South Australian Std Time */ - {"sat", DOW, 6}, - {"saturday", DOW, 6}, - {"sep", MONTH, 9}, - {"sept", MONTH, 9}, - {"september", MONTH, 9}, - {"set", TZ, NEG(6)}, /* Seychelles Time ?? */ - {"sst", DTZ, 12}, /* Swedish Summer Time */ - {"sun", DOW, 0}, - {"sunday", DOW, 0}, - {"swt", TZ, 6}, /* Swedish Winter Time */ - {"thu", DOW, 4}, - {"thur", DOW, 4}, - {"thurs", DOW, 4}, - {"thursday", DOW, 4}, - {TODAY, RESERV, DTK_TODAY}, /* midnight */ - {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */ - {"tue", DOW, 2}, - {"tues", DOW, 2}, - {"tuesday", DOW, 2}, - {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid - * time */ - {"ut", TZ, 0}, - {"utc", TZ, 0}, - {"wadt", DTZ, 48}, /* West Australian DST */ - {"wast", TZ, 42}, /* West Australian Std Time */ - {"wat", TZ, NEG(6)}, /* West Africa Time */ - {"wdt", DTZ, 54}, /* West Australian DST */ - {"wed", DOW, 3}, - {"wednesday", DOW, 3}, - {"weds", DOW, 3}, - {"wet", TZ, 0}, /* Western Europe */ - {"wetdst", DTZ, 6}, /* Western Europe */ - {"wst", TZ, 48}, /* West Australian Std Time */ - {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */ - {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */ - {"yst", TZ, NEG(54)}, /* Yukon Standard Time */ - {"zp4", TZ, NEG(24)}, /* GMT +4 hours. */ - {"zp5", TZ, NEG(30)}, /* GMT +5 hours. */ - {"zp6", TZ, NEG(36)}, /* GMT +6 hours. */ - {"z", RESERV, DTK_ZULU}, /* 00:00:00 */ - {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */ -}; - -static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]; - -static datetkn deltatktbl[] = { -/* text token lexval */ - {"@", IGNORE, 0}, /* postgres relative time prefix */ - {DAGO, AGO, 0}, /* "ago" indicates negative time offset */ - {"c", UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"cent", UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative time units */ - {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative time units */ - {"d", UNITS, DTK_DAY}, /* "day" relative time units */ - {DDAY, UNITS, DTK_DAY}, /* "day" relative time units */ - {"days", UNITS, DTK_DAY}, /* "days" relative time units */ - {"dec", UNITS, DTK_DECADE}, /* "decade" relative time units */ - {"decs", UNITS, DTK_DECADE},/* "decades" relative time units */ - {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative time units */ - {"decades", UNITS, DTK_DECADE}, /* "decades" relative time units */ - {"h", UNITS, DTK_HOUR}, /* "hour" relative time units */ - {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative time units */ - {"hours", UNITS, DTK_HOUR}, /* "hours" relative time units */ - {"hr", UNITS, DTK_HOUR}, /* "hour" relative time units */ - {"hrs", UNITS, DTK_HOUR}, /* "hours" relative time units */ - {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid - * time */ - {"m", UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative - * time units */ - {"mil", UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */ - {"mils", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */ - {"millenia", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */ - {DMILLENIUM, UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */ - {"millisecon", UNITS, DTK_MILLISEC}, /* relative time units */ - {"min", UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */ - {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */ - {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative time units */ - {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative time units */ - {"mon", UNITS, DTK_MONTH}, /* "months" relative time units */ - {"mons", UNITS, DTK_MONTH}, /* "months" relative time units */ - {DMONTH, UNITS, DTK_MONTH}, /* "month" relative time units */ - {"months", UNITS, DTK_MONTH}, - {"ms", UNITS, DTK_MILLISEC}, - {"msec", UNITS, DTK_MILLISEC}, - {DMILLISEC, UNITS, DTK_MILLISEC}, - {"mseconds", UNITS, DTK_MILLISEC}, - {"msecs", UNITS, DTK_MILLISEC}, - {"qtr", UNITS, DTK_QUARTER},/* "quarter" relative time */ - {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative time */ - {"reltime", IGNORE, 0}, /* for pre-v6.1 "Undefined Reltime" */ - {"s", UNITS, DTK_SECOND}, - {"sec", UNITS, DTK_SECOND}, - {DSECOND, UNITS, DTK_SECOND}, - {"seconds", UNITS, DTK_SECOND}, - {"secs", UNITS, DTK_SECOND}, - {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */ - {"tz", UNITS, DTK_TZ}, /* "timezone" time offset */ - {"tz_hour", UNITS, DTK_TZ_HOUR}, /* timezone hour units */ - {"tz_minute", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */ - {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */ - {"us", UNITS, DTK_MICROSEC},/* "microsecond" relative time units */ - {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative time - * units */ - {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative time - * units */ - {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative time - * units */ - {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative time - * units */ - {"w", UNITS, DTK_WEEK}, /* "week" relative time units */ - {DWEEK, UNITS, DTK_WEEK}, /* "week" relative time units */ - {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative time units */ - {"y", UNITS, DTK_YEAR}, /* "year" relative time units */ - {DYEAR, UNITS, DTK_YEAR}, /* "year" relative time units */ - {"years", UNITS, DTK_YEAR}, /* "years" relative time units */ - {"yr", UNITS, DTK_YEAR}, /* "year" relative time units */ - {"yrs", UNITS, DTK_YEAR}, /* "years" relative time units */ -}; - -static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0]; - -#if USE_DATE_CACHE -datetkn *datecache[MAXDATEFIELDS] = {NULL}; - -datetkn *deltacache[MAXDATEFIELDS] = {NULL}; - -#endif - - -/* - * Calendar time to Julian date conversions. - * Julian date is commonly used in astronomical applications, - * since it is numerically accurate and computationally simple. - * The algorithms here will accurately convert between Julian day - * and calendar date for all non-negative Julian days - * (i.e. from Nov 23, -4713 on). - * - * Ref: Explanatory Supplement to the Astronomical Almanac, 1992. - * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941. - * - * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague - * now at Aerospace Corp. (hi, Henry!) - * - * These routines will be used by other date/time packages - tgl 97/02/25 - */ - -int -date2j(int y, int m, int d) -{ - int m12 = (m - 14) / 12; - - return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12 - - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075); -} /* date2j() */ - -void -j2date(int jd, int *year, int *month, int *day) -{ - int j, - y, - m, - d; - - int i, - l, - n; - - l = jd + 68569; - n = (4 * l) / 146097; - l -= (146097 * n + 3) / 4; - i = (4000 * (l + 1)) / 1461001; - l += 31 - (1461 * i) / 4; - j = (80 * l) / 2447; - d = l - (2447 * j) / 80; - l = j / 11; - m = (j + 2) - (12 * l); - y = 100 * (n - 49) + i + l; - - *year = y; - *month = m; - *day = d; - return; -} /* j2date() */ - -static int -j2day(int date) -{ - int day; - - day = (date + 1) % 7; - - return day; -} /* j2day() */ - - -/* datetime2tm() - * Convert datetime data type to POSIX time structure. - * Note that year is _not_ 1900-based, but is an explicit full value. - * Also, month is one-based, _not_ zero-based. - * Returns: - * 0 on success - * -1 on out of range - * - * For dates within the system-supported time_t range, convert to the - * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 - */ -int -datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn) -{ - double date, - date0, - time, - sec; - time_t utime; - -#ifdef USE_POSIX_TIME - struct tm *tx; - -#endif - - date0 = date2j(2000, 1, 1); - - time = dt; - TMODULO(time, date, 86400e0); - - if (time < 0) - { - time += 86400; - date -= 1; - } - - /* Julian day routine does not work for negative Julian days */ - if (date < -date0) - return -1; - - /* add offset to go from J2000 back to standard Julian date */ - date += date0; - - j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - dt2time(time, &tm->tm_hour, &tm->tm_min, &sec); - - *fsec = JROUND(sec); - TMODULO(*fsec, tm->tm_sec, 1e0); - - if (tzp != NULL) - { - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { - utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400); - -#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_hour = tx->tm_hour; - tm->tm_min = tx->tm_min; -#if NOT_USED -/* XXX HACK - * Argh! My Linux box puts in a 1 second offset for dates less than 1970 - * but only if the seconds field was non-zero. So, don't copy the seconds - * field and instead carry forward from the original - tgl 97/06/18 - * Note that GNU/Linux uses the standard freeware zic package as do - * many other platforms so this may not be GNU/Linux/ix86-specific. - */ - tm->tm_sec = tx->tm_sec; -#endif - tm->tm_isdst = tx->tm_isdst; - -#if defined(HAVE_TM_ZONE) - tm->tm_gmtoff = tx->tm_gmtoff; - tm->tm_zone = tx->tm_zone; - - *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ - 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 - - } - else - { - *tzp = 0; - tm->tm_isdst = 0; - if (tzn != NULL) - *tzn = NULL; - } - - dt = dt2local(dt, *tzp); - - } - else - { - tm->tm_isdst = 0; - if (tzn != NULL) - *tzn = NULL; - } - - return 0; -} /* datetime2tm() */ - - -/* tm2datetime() - * Convert a tm structure to a datetime data type. - * Note that year is _not_ 1900-based, but is an explicit full value. - * Also, month is one-based, _not_ zero-based. - */ -int -tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime *result) -{ - - double date, - time; - - /* Julian day routines are not correct for negative Julian days */ - if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) - return -1; - - date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); - time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec)); - *result = (date * 86400 + time); - if (tzp != NULL) - *result = dt2local(*result, -(*tzp)); - - return 0; -} /* tm2datetime() */ - - -/* timespan2tm() - * Convert a timespan data type to a tm structure. - */ -static int -timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec) -{ - double time; - - if (span.month != 0) - { - tm->tm_year = span.month / 12; - tm->tm_mon = span.month % 12; - - } - else - { - tm->tm_year = 0; - tm->tm_mon = 0; - } - -#ifdef ROUND_ALL - time = JROUND(span.time); -#else - time = span.time; -#endif - - TMODULO(time, tm->tm_mday, 86400e0); - TMODULO(time, tm->tm_hour, 3600e0); - TMODULO(time, tm->tm_min, 60e0); - TMODULO(time, tm->tm_sec, 1e0); - *fsec = time; - - return 0; -} /* timespan2tm() */ - -static int -tm2timespan(struct tm * tm, double fsec, TimeSpan *span) -{ - span->month = ((tm->tm_year * 12) + tm->tm_mon); - span->time = ((((((tm->tm_mday * 24.0) - + tm->tm_hour) * 60.0) - + tm->tm_min) * 60.0) - + tm->tm_sec); - span->time = JROUND(span->time + fsec); - - return 0; -} /* tm2timespan() */ - - -static DateTime -dt2local(DateTime dt, int tz) -{ - dt -= tz; - dt = JROUND(dt); - return dt; -} /* dt2local() */ - -static double -time2t(const int hour, const int min, const double sec) -{ - return (((hour * 60) + min) * 60) + sec; -} /* time2t() */ - -static void -dt2time(DateTime jd, int *hour, int *min, double *sec) -{ - double time; - - time = jd; - - *hour = (time / 3600); - time -= ((*hour) * 3600); - *min = (time / 60); - time -= ((*min) * 60); - *sec = JROUND(time); - - return; -} /* dt2time() */ - - -/* - * parse and convert date in timestr (the normal interface) - * - * Returns the number of seconds since epoch (J2000) - */ - -/* ParseDateTime() - * Break string into tokens based on a date/time context. - */ -int -ParseDateTime(char *timestr, char *lowstr, - char **field, int *ftype, int maxfields, int *numfields) -{ - int nf = 0; - char *cp = timestr; - char *lp = lowstr; - - /* outer loop through fields */ - while (*cp != '\0') - { - field[nf] = lp; - - /* leading digit? then date or time */ - if (isdigit(*cp) || (*cp == '.')) - { - *lp++ = *cp++; - while (isdigit(*cp)) - *lp++ = *cp++; - /* time field? */ - if (*cp == ':') - { - ftype[nf] = DTK_TIME; - while (isdigit(*cp) || (*cp == ':') || (*cp == '.')) - *lp++ = *cp++; - - } - /* date field? allow embedded text month */ - else if ((*cp == '-') || (*cp == '/') || (*cp == '.')) - { - ftype[nf] = DTK_DATE; - while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.')) - *lp++ = tolower(*cp++); - - } - - /* - * otherwise, number only and will determine year, month, or - * day later - */ - else - ftype[nf] = DTK_NUMBER; - - } - - /* - * text? then date string, month, day of week, special, or - * timezone - */ - else if (isalpha(*cp)) - { - ftype[nf] = DTK_STRING; - *lp++ = tolower(*cp++); - while (isalpha(*cp)) - *lp++ = tolower(*cp++); - - /* full date string with leading text month? */ - if ((*cp == '-') || (*cp == '/') || (*cp == '.')) - { - /* - * special case of Posix timezone "GMT-0800" - * Note that other sign (e.g. "GMT+0800" - * is recognized as two separate fields and handled later. - * XXX There is no room for a delimiter between - * the "GMT" and the "-0800", so we are going to just swallow the "GMT". - * But this leads to other troubles with the definition of signs, - * so we have to flip - * - thomas 2000-02-06 - */ - if ((*cp == '-') && isdigit(*(cp+1)) - && (strncmp(field[nf], "gmt", 3) == 0)) - { - *cp = '+'; - continue; - } - - ftype[nf] = DTK_DATE; - while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.')) - *lp++ = tolower(*cp++); - } - - /* skip leading spaces */ - } - else if (isspace(*cp)) - { - cp++; - continue; - - /* sign? then special or numeric timezone */ - } - else if ((*cp == '+') || (*cp == '-')) - { - *lp++ = *cp++; - /* soak up leading whitespace */ - while (isspace(*cp)) - cp++; - /* numeric timezone? */ - if (isdigit(*cp)) - { - ftype[nf] = DTK_TZ; - *lp++ = *cp++; - while (isdigit(*cp) || (*cp == ':')) - *lp++ = *cp++; - - /* special? */ - } - else if (isalpha(*cp)) - { - ftype[nf] = DTK_SPECIAL; - *lp++ = tolower(*cp++); - while (isalpha(*cp)) - *lp++ = tolower(*cp++); - - /* otherwise something wrong... */ - } - else - return -1; - - /* ignore punctuation but use as delimiter */ - } - else if (ispunct(*cp)) - { - cp++; - continue; - - } - else - return -1; - - /* force in a delimiter */ - *lp++ = '\0'; - nf++; - if (nf > MAXDATEFIELDS) - return -1; - } - - *numfields = nf; - - return 0; -} /* ParseDateTime() */ - - -/* DecodeDateTime() - * Interpret previously parsed fields for general date and time. - * Return 0 if full date, 1 if only time, and -1 if problems. - * External format(s): - * " -- ::" - * "Fri Feb-7-1997 15:23:27" - * "Feb-7-1997 15:23:27" - * "2-7-1997 15:23:27" - * "1997-2-7 15:23:27" - * "1997.038 15:23:27" (day of year 1-366) - * Also supports input in compact time: - * "970207 152327" - * "97038 152327" - * - * Use the system-provided functions to get the current time zone - * if not specified in the input string. - * If the date is outside the time_t system-supported time range, - * then assume GMT time zone. - tgl 97/05/27 - */ -int -DecodeDateTime(char **field, int *ftype, int nf, - int *dtype, struct tm * tm, double *fsec, int *tzp) -{ - int fmask = 0, - tmask, - type; - int i; - int flen, - val; - int mer = HR24; - int haveTextMonth = FALSE; - int is2digits = FALSE; - int bc = FALSE; - - *dtype = DTK_DATE; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - *fsec = 0; - tm->tm_isdst = -1; /* don't know daylight savings time status - * apriori */ - if (tzp != NULL) - *tzp = 0; - - for (i = 0; i < nf; i++) - { - switch (ftype[i]) - { - case DTK_DATE: - if (DecodeDate(field[i], fmask, &tmask, tm) != 0) - return -1; - break; - - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - - /* - * check upper limit on hours; other limits checked in - * DecodeTime() - */ - if (tm->tm_hour > 23) - return -1; - break; - - case DTK_TZ: - if (tzp == NULL) - return -1; - if (DecodeTimezone(field[i], tzp) != 0) - return -1; - tmask = DTK_M(TZ); - break; - - case DTK_NUMBER: - flen = strlen(field[i]); - - /* - * long numeric string and either no date or no time read - * yet? then interpret as a concatenated date or time... - */ - if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M))) - { - if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - - } - /* otherwise it is a single date/time field... */ - else - { - if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - } - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = DTK_M(type); - switch (type) - { - case RESERV: - switch (val) - { - case DTK_NOW: - tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_DATE; - GetCurrentTime(tm); - if (tzp != NULL) - *tzp = CTimeZone; - break; - - case DTK_YESTERDAY: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_TODAY: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_TOMORROW: - tmask = DTK_DATE_M; - *dtype = DTK_DATE; - GetCurrentTime(tm); - j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - break; - - case DTK_ZULU: - tmask = (DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_DATE; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - if (tzp != NULL) - *tzp = 0; - break; - - default: - *dtype = val; - } - - break; - - case MONTH: - /* - * already have a (numeric) month? then see if we - * can substitute... - */ - if ((fmask & DTK_M(MONTH)) && (!haveTextMonth) - && (!(fmask & DTK_M(DAY))) - && ((tm->tm_mon >= 1) && (tm->tm_mon <= 31))) - { - tm->tm_mday = tm->tm_mon; - tmask = DTK_M(DAY); - } - haveTextMonth = TRUE; - tm->tm_mon = val; - break; - - case DTZMOD: - - /* - * daylight savings time modifier (solves "MET - * DST" syntax) - */ - tmask |= DTK_M(DTZ); - tm->tm_isdst = 1; - if (tzp == NULL) - return -1; - *tzp += val * 60; - break; - - case DTZ: - - /* - * set mask for TZ here _or_ check for DTZ later - * when getting default timezone - */ - tmask |= DTK_M(TZ); - tm->tm_isdst = 1; - if (tzp == NULL) - return -1; - *tzp = val * 60; - break; - - case TZ: - tm->tm_isdst = 0; - if (tzp == NULL) - return -1; - *tzp = val * 60; - - /* Swallow an immediately succeeding timezone if this is GMT - * This handles the odd case in FreeBSD of "GMT+0800" - * but note that we need to flip the sign on this too. - * Claims to be some sort of POSIX standard format :( - * - thomas 2000-01-20 - */ - if ((i < (nf-1)) && (ftype[i+1] == DTK_TZ) - && (strcmp(field[i], "gmt") == 0)) - { - i++; - if (DecodeTimezone(field[i], tzp) != 0) - return -1; - - /* flip the sign per POSIX standard */ - *tzp = -(*tzp); - } - - - break; - - case IGNORE: - break; - - case AMPM: - mer = val; - break; - - case ADBC: - bc = (val == BC); - break; - - case DOW: - tm->tm_wday = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ - if (bc) - { - if (tm->tm_year > 0) - tm->tm_year = -(tm->tm_year - 1); - else - elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year); - } - else if (is2digits) - { - if (tm->tm_year < 70) - tm->tm_year += 2000; - else if (tm->tm_year < 100) - tm->tm_year += 1900; - } - - if ((mer != HR24) && (tm->tm_hour > 12)) - return -1; - if ((mer == AM) && (tm->tm_hour == 12)) - tm->tm_hour = 0; - else if ((mer == PM) && (tm->tm_hour != 12)) - tm->tm_hour += 12; - - /* do additional checking for full date specs... */ - if (*dtype == DTK_DATE) - { - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1; - - /* - * check for valid day of month, now that we know for sure the - * month and year... - */ - if ((tm->tm_mday < 1) - || (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])) - return -1; - - /* timezone not specified? then find local timezone if possible */ - if (((fmask & DTK_DATE_M) == DTK_DATE_M) - && (tzp != NULL) && (!(fmask & DTK_M(TZ)))) - { - - /* - * daylight savings time modifier but no standard timezone? - * then error - */ - if (fmask & DTK_M(DTZMOD)) - return -1; - - if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) - { -#ifdef USE_POSIX_TIME - tm->tm_year -= 1900; - tm->tm_mon -= 1; - tm->tm_isdst = -1; - mktime(tm); - tm->tm_year += 1900; - tm->tm_mon += 1; - -#if defined(HAVE_TM_ZONE) - *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is - * Sun/DEC-ism */ -#elif defined(HAVE_INT_TIMEZONE) -#ifdef __CYGWIN__ - *tzp = ((tm->tm_isdst > 0) ? (_timezone - 3600) : _timezone); -#else - *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone); -#endif -#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; -#endif - } - else - { - tm->tm_isdst = 0; - *tzp = 0; - } - } - } - - return 0; -} /* DecodeDateTime() */ - - -/* DecodeTimeOnly() - * Interpret parsed string as time fields only. - */ -int -DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec) -{ - int fmask, - tmask, - type; - int i; - int flen, - val; - int is2digits = FALSE; - int mer = HR24; - - *dtype = DTK_TIME; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - tm->tm_isdst = -1; /* don't know daylight savings time status - * apriori */ - *fsec = 0; - - fmask = DTK_DATE_M; - - for (i = 0; i < nf; i++) - { - switch (ftype[i]) - { - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - break; - - case DTK_NUMBER: - flen = strlen(field[i]); - - if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0) - return -1; - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = DTK_M(type); - switch (type) - { - case RESERV: - switch (val) - { - case DTK_NOW: - tmask = DTK_TIME_M; - *dtype = DTK_TIME; - GetCurrentTime(tm); - break; - - case DTK_ZULU: - tmask = (DTK_TIME_M | DTK_M(TZ)); - *dtype = DTK_TIME; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - tm->tm_isdst = 0; - break; - - default: - return -1; - } - - break; - - case IGNORE: - break; - - case AMPM: - mer = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - if ((mer != HR24) && (tm->tm_hour > 12)) - return -1; - if ((mer == AM) && (tm->tm_hour == 12)) - tm->tm_hour = 0; - else if ((mer == PM) && (tm->tm_hour != 12)) - tm->tm_hour += 12; - - if (((tm->tm_hour < 0) || (tm->tm_hour > 23)) - || ((tm->tm_min < 0) || (tm->tm_min > 59)) - || ((tm->tm_sec < 0) || ((tm->tm_sec + *fsec) >= 60))) - return -1; - - if ((fmask & DTK_TIME_M) != DTK_TIME_M) - return -1; - - return 0; -} /* DecodeTimeOnly() */ - - -/* DecodeDate() - * Decode date string which includes delimiters. - * Insist on a complete set of fields. - */ -static int -DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) -{ - double fsec; - - int nf = 0; - int i, - len; - int bc = FALSE; - int is2digits = FALSE; - int type, - val, - dmask = 0; - char *field[MAXDATEFIELDS]; - - /* parse this string... */ - while ((*str != '\0') && (nf < MAXDATEFIELDS)) - { - /* skip field separators */ - while (!isalnum(*str)) - str++; - - field[nf] = str; - if (isdigit(*str)) - { - while (isdigit(*str)) - str++; - } - else if (isalpha(*str)) - { - while (isalpha(*str)) - str++; - } - - if (*str != '\0') - *str++ = '\0'; - nf++; - } - -#if 0 - /* don't allow too many fields */ - if (nf > 3) - return -1; -#endif - - *tmask = 0; - - /* look first for text fields, since that will be unambiguous month */ - for (i = 0; i < nf; i++) - { - if (isalpha(*field[i])) - { - type = DecodeSpecial(i, field[i], &val); - if (type == IGNORE) - continue; - - dmask = DTK_M(type); - switch (type) - { - case MONTH: - tm->tm_mon = val; - break; - - case ADBC: - bc = (val == BC); - break; - - default: - return -1; - } - if (fmask & dmask) - return -1; - - fmask |= dmask; - *tmask |= dmask; - - /* mark this field as being completed */ - field[i] = NULL; - } - } - - /* now pick up remaining numeric fields */ - for (i = 0; i < nf; i++) - { - if (field[i] == NULL) - continue; - - if ((len = strlen(field[i])) <= 0) - return -1; - - if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits) != 0) - return -1; - - if (fmask & dmask) - return -1; - - fmask |= dmask; - *tmask |= dmask; - } - - if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M) - return -1; - - /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ - if (bc) - { - if (tm->tm_year > 0) - tm->tm_year = -(tm->tm_year - 1); - else - elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year); - } - else if (is2digits) - { - if (tm->tm_year < 70) - tm->tm_year += 2000; - else if (tm->tm_year < 100) - tm->tm_year += 1900; - } - - return 0; -} /* DecodeDate() */ - - -/* DecodeTime() - * Decode time string which includes delimiters. - * Only check the lower limit on hours, since this same code - * can be used to represent time spans. - */ -static int -DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec) -{ - char *cp; - - *tmask = DTK_TIME_M; - - tm->tm_hour = strtol(str, &cp, 10); - if (*cp != ':') - return -1; - str = cp + 1; - tm->tm_min = strtol(str, &cp, 10); - if (*cp == '\0') - { - tm->tm_sec = 0; - *fsec = 0; - - } - else if (*cp != ':') - { - return -1; - - } - else - { - str = cp + 1; - tm->tm_sec = strtol(str, &cp, 10); - if (*cp == '\0') - *fsec = 0; - else if (*cp == '.') - { - str = cp; - *fsec = strtod(str, &cp); - if (cp == str) - return -1; - } - else - return -1; - } - - /* do a sanity check */ - if ((tm->tm_hour < 0) - || (tm->tm_min < 0) || (tm->tm_min > 59) - || (tm->tm_sec < 0) || (tm->tm_sec > 59)) - return -1; - - return 0; -} /* DecodeTime() */ - - -/* DecodeNumber() - * Interpret numeric field as a date value in context. - */ -static int -DecodeNumber(int flen, char *str, int fmask, - int *tmask, struct tm * tm, double *fsec, int *is2digits) -{ - int val; - char *cp; - - *tmask = 0; - - val = strtol(str, &cp, 10); - if (cp == str) - return -1; - if (*cp == '.') - { - *fsec = strtod(cp, &cp); - if (*cp != '\0') - return -1; - } - - /* Special case day of year? */ - if ((flen == 3) && (fmask & DTK_M(YEAR)) - && ((val >= 1) && (val <= 366))) - { - *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY)); - tm->tm_yday = val; - j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1), - &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - - } - - /* - * Enough digits to be unequivocal year? Used to test for 4 digits or - * more, but we now test first for a three-digit doy so anything - * bigger than two digits had better be an explicit year. - thomas - * 1999-01-09 - */ - else if (flen > 2) - { - *tmask = DTK_M(YEAR); - - /* already have a year? then see if we can substitute... */ - if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY))) - && ((tm->tm_year >= 1) && (tm->tm_year <= 31))) - { - tm->tm_mday = tm->tm_year; - *tmask = DTK_M(DAY); - } - - tm->tm_year = val; - } - /* already have year? then could be month */ - else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH))) - && ((val >= 1) && (val <= 12))) - { - *tmask = DTK_M(MONTH); - tm->tm_mon = val; - /* no year and EuroDates enabled? then could be day */ - } - else if ((EuroDates || (fmask & DTK_M(MONTH))) - && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY))) - && ((val >= 1) && (val <= 31))) - { - *tmask = DTK_M(DAY); - tm->tm_mday = val; - } - else if ((!(fmask & DTK_M(MONTH))) - && ((val >= 1) && (val <= 12))) - { - *tmask = DTK_M(MONTH); - tm->tm_mon = val; - } - else if ((!(fmask & DTK_M(DAY))) - && ((val >= 1) && (val <= 31))) - { - *tmask = DTK_M(DAY); - tm->tm_mday = val; - } - else if (!(fmask & DTK_M(YEAR))) - { - *tmask = DTK_M(YEAR); - tm->tm_year = val; - - /* adjust ONLY if exactly two digits... */ - *is2digits = (flen == 2); - } - else - return -1; - - return 0; -} /* DecodeNumber() */ - - -/* DecodeNumberField() - * Interpret numeric string as a concatenated date field. - */ -static int -DecodeNumberField(int len, char *str, int fmask, - int *tmask, struct tm * tm, double *fsec, int *is2digits) -{ - char *cp; - - /* yyyymmdd? */ - if (len == 8) - { - *tmask = DTK_DATE_M; - - tm->tm_mday = atoi(str + 6); - *(str + 6) = '\0'; - tm->tm_mon = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_year = atoi(str + 0); - /* yymmdd or hhmmss? */ - } - else if (len == 6) - { - if (fmask & DTK_DATE_M) - { - *tmask = DTK_TIME_M; - tm->tm_sec = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_min = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_hour = atoi(str + 0); - } - else - { - *tmask = DTK_DATE_M; - tm->tm_mday = atoi(str + 4); - *(str + 4) = '\0'; - tm->tm_mon = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_year = atoi(str + 0); - *is2digits = TRUE; - } - - } - else if ((len == 5) && !(fmask & DTK_DATE_M)) - { - *tmask = DTK_DATE_M; - tm->tm_mday = atoi(str + 2); - *(str + 2) = '\0'; - tm->tm_mon = 1; - tm->tm_year = atoi(str + 0); - *is2digits = TRUE; - } - else if (strchr(str, '.') != NULL) - { - *tmask = DTK_TIME_M; - tm->tm_sec = strtod((str + 4), &cp); - if (cp == (str + 4)) - return -1; - if (*cp == '.') - *fsec = strtod(cp, NULL); - *(str + 4) = '\0'; - tm->tm_min = strtod((str + 2), &cp); - *(str + 2) = '\0'; - tm->tm_hour = strtod((str + 0), &cp); - - } - else - return -1; - - return 0; -} /* DecodeNumberField() */ - - -/* DecodeTimezone() - * Interpret string as a numeric timezone. - */ -static int -DecodeTimezone(char *str, int *tzp) -{ - int tz; - int hr, - min; - char *cp; - int len; - - /* assume leading character is "+" or "-" */ - hr = strtol((str + 1), &cp, 10); - - /* explicit delimiter? */ - if (*cp == ':') - { - min = strtol((cp + 1), &cp, 10); - - /* otherwise, might have run things together... */ - } - else if ((*cp == '\0') && ((len = strlen(str)) > 3)) - { - min = strtol((str + len - 2), &cp, 10); - *(str + len - 2) = '\0'; - hr = strtol((str + 1), &cp, 10); - - } - else - min = 0; - - tz = (hr * 60 + min) * 60; - if (*str == '-') - tz = -tz; - - *tzp = -tz; - return *cp != '\0'; -} /* DecodeTimezone() */ - - -/* DecodeSpecial() - * Decode text string using lookup table. - * Implement a cache lookup since it is likely that dates - * will be related in format. - */ -static int -DecodeSpecial(int field, char *lowtoken, int *val) -{ - int type; - datetkn *tp; - -#if USE_DATE_CACHE - if ((datecache[field] != NULL) - && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)) - tp = datecache[field]; - else - { -#endif - tp = datebsearch(lowtoken, datetktbl, szdatetktbl); -#if USE_DATE_CACHE - } - datecache[field] = tp; -#endif - if (tp == NULL) - { - type = IGNORE; - *val = 0; - } - else - { - type = tp->type; - switch (type) - { - case TZ: - case DTZ: - case DTZMOD: - *val = FROMVAL(tp); - break; - - default: - *val = tp->value; - break; - } - } - - return type; -} /* DecodeSpecial() */ - - -/* DecodeDateDelta() - * Interpret previously parsed fields for general time interval. - * Return 0 if decoded and -1 if problems. - * - * Allow "date" field DTK_DATE since this could be just - * an unsigned floating point number. - thomas 1997-11-16 - * - * Allow ISO-style time span, with implicit units on number of days - * preceeding an hh:mm:ss field. - thomas 1998-04-30 - */ -int -DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec) -{ - int is_before = FALSE; - - char *cp; - int fmask = 0, - tmask, - type; - int i; - int flen, - val; - double fval; - double sec; - - *dtype = DTK_DELTA; - - type = DTK_SECOND; - tm->tm_year = 0; - tm->tm_mon = 0; - tm->tm_mday = 0; - tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - *fsec = 0; - - /* read through list backwards to pick up units before values */ - for (i = nf - 1; i >= 0; i--) - { - switch (ftype[i]) - { - case DTK_TIME: - if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) - return -1; - type = DTK_DAY; - break; - - case DTK_TZ: - - /* - * Timezone is a token with a leading sign character and - * otherwise the same as a non-signed numeric field - */ - case DTK_DATE: - case DTK_NUMBER: - val = strtol(field[i], &cp, 10); - if (*cp == '.') - { - fval = strtod(cp, &cp); - if (*cp != '\0') - return -1; - - if (val < 0) - fval = -(fval); - } - else if (*cp == '\0') - fval = 0; - else - return -1; - - flen = strlen(field[i]); - tmask = 0; /* DTK_M(type); */ - - switch (type) - { - case DTK_MICROSEC: - *fsec += ((val + fval) * 1e-6); - break; - - case DTK_MILLISEC: - *fsec += ((val + fval) * 1e-3); - break; - - case DTK_SECOND: - tm->tm_sec += val; - *fsec += fval; - tmask = DTK_M(SECOND); - break; - - case DTK_MINUTE: - tm->tm_min += val; - if (fval != 0) - tm->tm_sec += (fval * 60); - tmask = DTK_M(MINUTE); - break; - - case DTK_HOUR: - tm->tm_hour += val; - if (fval != 0) - tm->tm_sec += (fval * 3600); - tmask = DTK_M(HOUR); - break; - - case DTK_DAY: - tm->tm_mday += val; - if (fval != 0) - tm->tm_sec += (fval * 86400); - tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); - break; - - case DTK_WEEK: - tm->tm_mday += val * 7; - if (fval != 0) - tm->tm_sec += (fval * (7 * 86400)); - tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); - break; - - case DTK_MONTH: - tm->tm_mon += val; - if (fval != 0) - tm->tm_sec += (fval * (30 * 86400)); - tmask = DTK_M(MONTH); - break; - - case DTK_YEAR: - tm->tm_year += val; - if (fval != 0) - tm->tm_mon += (fval * 12); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_DECADE: - tm->tm_year += val * 10; - if (fval != 0) - tm->tm_mon += (fval * 120); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_CENTURY: - tm->tm_year += val * 100; - if (fval != 0) - tm->tm_mon += (fval * 1200); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - case DTK_MILLENIUM: - tm->tm_year += val * 1000; - if (fval != 0) - tm->tm_mon += (fval * 12000); - tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); - break; - - default: - return -1; - } - break; - - case DTK_STRING: - case DTK_SPECIAL: - type = DecodeUnits(i, field[i], &val); - if (type == IGNORE) - continue; - - tmask = 0; /* DTK_M(type); */ - switch (type) - { - case UNITS: - type = val; - break; - - case AGO: - is_before = TRUE; - type = val; - break; - - case RESERV: - tmask = (DTK_DATE_M || DTK_TIME_M); - *dtype = val; - break; - - default: - return -1; - } - break; - - default: - return -1; - } - - if (tmask & fmask) - return -1; - fmask |= tmask; - } - - if (*fsec != 0) - { - TMODULO(*fsec, sec, 1e0); - tm->tm_sec += sec; - } - - if (is_before) - { - *fsec = -(*fsec); - tm->tm_sec = -(tm->tm_sec); - tm->tm_min = -(tm->tm_min); - tm->tm_hour = -(tm->tm_hour); - tm->tm_mday = -(tm->tm_mday); - tm->tm_mon = -(tm->tm_mon); - tm->tm_year = -(tm->tm_year); - } - - /* ensure that at least one time field has been found */ - return (fmask != 0) ? 0 : -1; -} /* DecodeDateDelta() */ - - -/* DecodeUnits() - * Decode text string using lookup table. - * This routine supports time interval decoding. - */ -static int -DecodeUnits(int field, char *lowtoken, int *val) -{ - int type; - datetkn *tp; - -#if USE_DATE_CACHE - if ((deltacache[field] != NULL) - && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)) - tp = deltacache[field]; - else - { -#endif - tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); -#if USE_DATE_CACHE - } - deltacache[field] = tp; -#endif - if (tp == NULL) - { - type = IGNORE; - *val = 0; - } - else - { - type = tp->type; - if ((type == TZ) || (type == DTZ)) - *val = FROMVAL(tp); - else - *val = tp->value; - } - - return type; -} /* DecodeUnits() */ - - -/* datebsearch() - * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this - * is WAY faster than the generic bsearch(). - */ -static datetkn * -datebsearch(char *key, datetkn *base, unsigned int nel) -{ - datetkn *last = base + nel - 1, - *position; - int result; - - while (last >= base) - { - position = base + ((last - base) >> 1); - result = key[0] - position->token[0]; - if (result == 0) - { - result = strncmp(key, position->token, TOKMAXLEN); - if (result == 0) - return position; - } - if (result < 0) - last = position - 1; - else - base = position + 1; - } - return NULL; -} - - -/* EncodeSpecialDateTime() - * Convert reserved datetime data type to string. - */ -static int -EncodeSpecialDateTime(DateTime dt, char *str) -{ - if (DATETIME_IS_RESERVED(dt)) - { - if (DATETIME_IS_INVALID(dt)) - strcpy(str, INVALID); - else if (DATETIME_IS_NOBEGIN(dt)) - strcpy(str, EARLY); - else if (DATETIME_IS_NOEND(dt)) - strcpy(str, LATE); - else if (DATETIME_IS_CURRENT(dt)) - strcpy(str, DCURRENT); - else if (DATETIME_IS_EPOCH(dt)) - strcpy(str, EPOCH); - else - strcpy(str, INVALID); - return TRUE; - } - - return FALSE; -} /* EncodeSpecialDateTime() */ - - -/* EncodeDateOnly() - * Encode date as local time. - */ -int -EncodeDateOnly(struct tm * tm, int style, char *str) -{ - if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) - return -1; - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - if (tm->tm_year > 0) - sprintf(str, "%04d-%02d-%02d", - tm->tm_year, tm->tm_mon, tm->tm_mday); - else - sprintf(str, "%04d-%02d-%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); - break; - - /* compatible with Oracle/Ingres date formats */ - case USE_SQL_DATES: - if (EuroDates) - sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); - if (tm->tm_year > 0) - sprintf((str + 5), "/%04d", tm->tm_year); - else - sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC"); - break; - - /* German-style date format */ - case USE_GERMAN_DATES: - sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); - if (tm->tm_year > 0) - sprintf((str + 5), ".%04d", tm->tm_year); - else - sprintf((str + 5), ".%04d %s", -(tm->tm_year - 1), "BC"); - break; - - /* traditional date-only style for Postgres */ - case USE_POSTGRES_DATES: - default: - if (EuroDates) - sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday); - if (tm->tm_year > 0) - sprintf((str + 5), "-%04d", tm->tm_year); - else - sprintf((str + 5), "-%04d %s", -(tm->tm_year - 1), "BC"); - break; - } - - return TRUE; -} /* EncodeDateOnly() */ - - -/* EncodeTimeOnly() - * Encode time fields only. - */ -int -EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str) -{ - double sec; - - if ((tm->tm_hour < 0) || (tm->tm_hour > 24)) - return -1; - - sec = (tm->tm_sec + fsec); - - sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min); - sprintf((str + 6), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec); - - return TRUE; -} /* EncodeTimeOnly() */ - - -/* EncodeDateTime() - * Encode date and time interpreted as local time. - * Support several date styles: - * Postgres - day mon hh:mm:ss yyyy tz - * SQL - mm/dd/yyyy hh:mm:ss.ss tz - * ISO - yyyy-mm-dd hh:mm:ss+/-tz - * German - dd.mm/yyyy hh:mm:ss tz - * Variants (affects order of month and day for Postgres and SQL styles): - * US - mm/dd/yyyy - * European - dd/mm/yyyy - */ -int -EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str) -{ - int day, - hour, - min; - double sec; - - if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) - return -1; - - sec = (tm->tm_sec + fsec); - - switch (style) - { - /* compatible with ISO date formats */ - - case USE_ISO_DATES: - if (tm->tm_year > 0) - { - sprintf(str, "%04d-%02d-%02d %02d:%02d:", - tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); - sprintf((str + 17), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - if (tzp != NULL) - { - hour = -(*tzp / 3600); - min = ((abs(*tzp) / 60) % 60); - } - else - { - hour = 0; - min = 0; - } - sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min); - } - - } - else - { - if (tm->tm_hour || tm->tm_min) - sprintf(str, "%04d-%02d-%02d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC"); - else - sprintf(str, "%04d-%02d-%02d %s", - -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); - } - break; - - /* compatible with Oracle/Ingres date formats */ - case USE_SQL_DATES: - if (EuroDates) - sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon); - else - sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday); - - if (tm->tm_year > 0) - { - sprintf((str + 5), "/%04d %02d:%02d:%05.2f", - tm->tm_year, tm->tm_hour, tm->tm_min, sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 22), " "); - strcpy((str + 23), *tzn); - } - - } - else - sprintf((str + 5), "/%04d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC"); - break; - - /* German variant on European style */ - case USE_GERMAN_DATES: - sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon); - if (tm->tm_year > 0) - { - sprintf((str + 5), ".%04d %02d:%02d:%05.2f", - tm->tm_year, tm->tm_hour, tm->tm_min, sec); - - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 22), " "); - strcpy((str + 23), *tzn); - } - - } - else - sprintf((str + 5), ".%04d %02d:%02d %s", - -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC"); - break; - - /* backward-compatible with traditional Postgres abstime dates */ - case USE_POSTGRES_DATES: - default: - day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); - tm->tm_wday = j2day(day); - - strncpy(str, days[tm->tm_wday], 3); - strcpy((str + 3), " "); - - if (EuroDates) - sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]); - else - sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday); - - if (tm->tm_year > 0) - { - sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min); - if (fsec != 0) - { - sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year); - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 27), " "); - strncpy((str + 28), *tzn, MAXTZLEN); - } - } - else - { - sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year); - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - { - strcpy((str + 24), " "); - strncpy((str + 25), *tzn, MAXTZLEN); - } - } - - } - else - { - sprintf((str + 10), " %02d:%02d %04d %s", - tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC"); - } - break; - } - - return TRUE; -} /* EncodeDateTime() */ - - -/* EncodeTimeSpan() - * Interpret time structure as a delta time and convert to string. - * - * Support "traditional Postgres" and ISO-8601 styles. - * Actually, afaik ISO does not address time interval formatting, - * but this looks similar to the spec for absolute date/time. - * - thomas 1998-04-30 - */ -int -EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str) -{ - int is_before = FALSE; - int is_nonzero = FALSE; - char *cp = str; - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - break; - - default: - strcpy(cp, "@ "); - cp += strlen(cp); - break; - } - - if (tm->tm_year != 0) - { - is_before |= (tm->tm_year < 0); - sprintf(cp, "%d year%s", - abs(tm->tm_year), ((abs(tm->tm_year) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - if (tm->tm_mon != 0) - { - is_before |= (tm->tm_mon < 0); - sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""), - abs(tm->tm_mon), ((abs(tm->tm_mon) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - switch (style) - { - /* compatible with ISO date formats */ - case USE_ISO_DATES: - if (tm->tm_mday != 0) - { - is_before |= (tm->tm_mday < 0); - sprintf(cp, "%s%d", (is_nonzero ? " " : ""), abs(tm->tm_mday)); - cp += strlen(cp); - is_nonzero = TRUE; - } - is_before |= ((tm->tm_hour < 0) || (tm->tm_min < 0)); - sprintf(cp, "%s%02d:%02d", (is_nonzero ? " " : ""), - abs(tm->tm_hour), abs(tm->tm_min)); - cp += strlen(cp); - if ((tm->tm_hour != 0) || (tm->tm_min != 0)) - is_nonzero = TRUE; - - /* fractional seconds? */ - if (fsec != 0) - { - fsec += tm->tm_sec; - is_before |= (fsec < 0); - sprintf(cp, ":%05.2f", fabs(fsec)); - cp += strlen(cp); - is_nonzero = TRUE; - - /* otherwise, integer seconds only? */ - } - else if (tm->tm_sec != 0) - { - is_before |= (tm->tm_sec < 0); - sprintf(cp, ":%02d", abs(tm->tm_sec)); - cp += strlen(cp); - is_nonzero = TRUE; - } - break; - - case USE_POSTGRES_DATES: - default: - if (tm->tm_mday != 0) - { - is_before |= (tm->tm_mday < 0); - sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""), - abs(tm->tm_mday), ((abs(tm->tm_mday) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - if (tm->tm_hour != 0) - { - is_before |= (tm->tm_hour < 0); - sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""), - abs(tm->tm_hour), ((abs(tm->tm_hour) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - if (tm->tm_min != 0) - { - is_before |= (tm->tm_min < 0); - sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""), - abs(tm->tm_min), ((abs(tm->tm_min) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - - /* fractional seconds? */ - if (fsec != 0) - { - fsec += tm->tm_sec; - is_before |= (fsec < 0); - sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), fabs(fsec)); - cp += strlen(cp); - is_nonzero = TRUE; - - /* otherwise, integer seconds only? */ - } - else if (tm->tm_sec != 0) - { - is_before |= (tm->tm_sec < 0); - sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""), - abs(tm->tm_sec), ((abs(tm->tm_sec) != 1) ? "s" : "")); - cp += strlen(cp); - is_nonzero = TRUE; - } - break; - } - - /* identically zero? then put in a unitless zero... */ - if (!is_nonzero) - { - strcat(cp, "0"); - cp += strlen(cp); - } - - if (is_before) - { - strcat(cp, " ago"); - cp += strlen(cp); - } - - return 0; -} /* EncodeTimeSpan() */ - - -#if defined(linux) && defined(__powerpc__) -int -datetime_is_epoch(double j) -{ - static union - { - double epoch; - unsigned char c[8]; - } u; - - u.c[0] = 0x80; /* sign bit */ - u.c[1] = 0x10; /* DBL_MIN */ - - return j == u.epoch; -} -int -datetime_is_current(double j) -{ - static union - { - double current; - unsigned char c[8]; - } u; - - u.c[1] = 0x10; /* DBL_MIN */ - - return j == u.current; -} - -#endif diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index e8f6d2cd47..7281d4f4dc 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,45 +1,45 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.3 2000/02/08 15:56:55 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.4 2000/02/16 17:24:48 thomas Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc * * - * TO_CHAR(); TO_DATETIME(); TO_DATE(); TO_NUMBER(); + * TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER(); * - * The PostgreSQL routines for a DateTime/int/float/numeric formatting, + * The PostgreSQL routines for a timestamp/int/float/numeric formatting, * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * * * Cache & Memory: * Routines use (itself) internal cache for format pictures. If - * new format arg is same as a last format string, routines not + * new format arg is same as a last format string, routines do not * call the format-parser. * - * The cache use static buffer and is persistent across transactions. If - * format-picture is bigger than cache buffer, parser is called always. + * The cache uses a static buffer and is persistent across transactions. + * If format-picture is bigger than cache buffer, parser is called always. * * NOTE for Number version: * All in this version is implemented as keywords ( => not used * suffixes), because a format picture is for *one* item (number) - * only. It not is as a datetime version, where each keyword (can) + * only. It not is as a timestamp version, where each keyword (can) * has suffix. * - * NOTE for DateTime version: - * In this modul is *not* used POSIX 'struct tm' type, but + * NOTE for Timestamp routines: + * In this module the POSIX 'struct tm' type is *not* used, but rather * PgSQL type, which has tm_mon based on one (*non* zero) and * year *not* based on 1900, but is used full year number. - * Modul support AC / BC years. + * Module supports AC / BC years. * * Supported types for to_char(): * - * Timestamp, DateTime, Numeric, int4, int8, float4, float8 + * Timestamp, Numeric, int4, int8, float4, float8 * * Supported types for reverse conversion: * - * Datetime - to_datetime() + * Timestamp - to_timestamp() * Date - to_date() * Numeric - to_number() * @@ -108,7 +108,7 @@ #define MAXDOUBLEWIDTH 128 /* ---------- - * External (defined in PgSQL dt.c (datetime utils)) + * External (defined in PgSQL dt.c (timestamp utils)) * ---------- */ extern char *months[], /* month abbreviation */ @@ -1377,14 +1377,14 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): SSSS is not supported"); + elog(ERROR, "to_datatime(): SSSS is not supported"); } return -1; } #define CHECK_SEQ_SEARCH(_l, _s) { \ if (_l <= 0) { \ - elog(ERROR, "to_datatime()/to_timestamp(): bad value for %s", _s); \ + elog(ERROR, "to_datatime(): bad value for %s", _s); \ } \ } @@ -1600,7 +1600,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): WW is not supported"); + elog(ERROR, "to_datatime(): WW is not supported"); case DCH_Q: if (flag == TO_CHAR) { sprintf(inout, "%d", (tm->tm_mon-1)/3+1); @@ -1611,7 +1611,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 0; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): Q is not supported"); + elog(ERROR, "to_datatime(): Q is not supported"); case DCH_CC: if (flag == TO_CHAR) { @@ -1625,7 +1625,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): CC is not supported"); + elog(ERROR, "to_datatime(): CC is not supported"); case DCH_Y_YYY: if (flag == TO_CHAR) { i= YEAR_ABS(tm->tm_year) / 1000; @@ -1764,7 +1764,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 0; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): W is not supported"); + elog(ERROR, "to_datatime(): W is not supported"); case DCH_J: if (flag == TO_CHAR) { @@ -1773,7 +1773,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime()/to_timestamp(): J is not supported"); + elog(ERROR, "to_datatime(): J is not supported"); } return -1; } @@ -1783,11 +1783,11 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ***************************************************************************/ /* ------------------- - * DATETIME to_char() + * TIMESTAMP to_char() * ------------------- */ text * -datetime_to_char(DateTime *dt, text *fmt) +timestamp_to_char(Timestamp *dt, text *fmt) { static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; static char CacheStr[ DCH_CACHE_SIZE +1]; @@ -1814,14 +1814,14 @@ datetime_to_char(DateTime *dt, text *fmt) tm->tm_mday =1; tm->tm_isdst =0; tm->tm_mon =1; - if (DATETIME_IS_EPOCH(*dt)) + if (TIMESTAMP_IS_EPOCH(*dt)) { - datetime2tm(SetDateTime(*dt), NULL, tm, &fsec, NULL); - } else if (DATETIME_IS_CURRENT(*dt)) { - datetime2tm(SetDateTime(*dt), &tz, tm, &fsec, &tzn); + timestamp2tm(SetTimestamp(*dt), NULL, tm, &fsec, NULL); + } else if (TIMESTAMP_IS_CURRENT(*dt)) { + timestamp2tm(SetTimestamp(*dt), &tz, tm, &fsec, &tzn); } else { - if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "to_char(): Unable to convert datetime to tm"); + if (timestamp2tm(*dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "to_char(): Unable to convert timestamp to tm"); } tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7; @@ -1902,32 +1902,22 @@ datetime_to_char(DateTime *dt, text *fmt) } -/* ------------------- - * TIMESTAMP to_char() - * ------------------- - */ -text * -timestamp_to_char(time_t dt, text *fmt) -{ - return datetime_to_char( timestamp_datetime(dt), fmt); -} - /* --------------------- - * TO_DATETIME() + * TO_TIMESTAMP() * - * Make DateTime from date_str which is formated at argument 'fmt' - * ( to_datetime is reverse to_char() ) + * Make Timestamp from date_str which is formated at argument 'fmt' + * ( to_timestamp is reverse to_char() ) * --------------------- */ -DateTime * -to_datetime(text *date_str, text *fmt) +Timestamp * +to_timestamp(text *date_str, text *fmt) { static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; static char CacheStr[ DCH_CACHE_SIZE +1]; FormatNode *format; int flag=0; - DateTime *result; + Timestamp *result; char *str; int len=0, fsec=0, @@ -1942,7 +1932,7 @@ to_datetime(text *date_str, text *fmt) tm->tm_mday =1; tm->tm_isdst =0; tm->tm_mon =1; - result = palloc(sizeof(DateTime)); + result = palloc(sizeof(Timestamp)); len = VARSIZE(fmt) - VARHDRSZ; @@ -2060,8 +2050,8 @@ to_datetime(text *date_str, text *fmt) #ifdef DEBUG_TO_FROM_CHAR NOTICE_TM; #endif - if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "to_datatime()/to_timestamp(): can't convert 'tm' to datetime."); + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "to_datatime(): can't convert 'tm' to timestamp."); return result; } @@ -2074,18 +2064,7 @@ to_datetime(text *date_str, text *fmt) DateADT to_date(text *date_str, text *fmt) { - return datetime_date( to_datetime(date_str, fmt) ); -} - -/* ---------- - * TO_TIMESTAMP - * Make timestamp from date_str which is formated at argument 'fmt' - * ---------- - */ -time_t -to_timestamp(text *date_str, text *fmt) -{ - return datetime_timestamp( to_datetime(date_str, fmt) ); + return timestamp_date( to_timestamp(date_str, fmt) ); } /********************************************************************** diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 71a636feeb..28a94f5e16 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -1,23 +1,41 @@ /* * nabstime.c - * parse almost any absolute date getdate(3) can (& some it can't) + * Utilities for the built-in type "AbsoluteTime". + * Functions for the built-in type "RelativeTime". + * Functions for the built-in type "TimeInterval". * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nabstime.c,v 1.65 2000/01/26 05:57:14 momjian Exp $ * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.66 2000/02/16 17:24:48 thomas Exp $ + * + * NOTES + * + *------------------------------------------------------------------------- */ #include +#include +#include #include #include "postgres.h" #ifdef HAVE_FLOAT_H #include #endif + #ifdef HAVE_LIMITS_H #include +#ifndef MAXINT +#define MAXINT INT_MAX #endif +#else +#ifdef HAVE_VALUES_H +#include +#endif +#endif + #ifndef USE_POSIX_TIME #include #endif @@ -26,11 +44,80 @@ #include "miscadmin.h" #include "utils/builtins.h" + +#if 0 static AbsoluteTime tm2abstime(struct tm * tm, int tz); +#endif + #define MIN_DAYNUM -24856 /* December 13, 1901 */ #define MAX_DAYNUM 24854 /* January 18, 2038 */ +#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 + * for these 4-byte types. + * + * "tinterval" is two 4-byte fields. + * Definitions for parsing tinterval. + */ + +#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 istinterval(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end); /* GetCurrentAbsoluteTime() * Get the current system time. Set timezone parameters if not specified elsewhere. @@ -491,10 +578,10 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2) /* datetime_abstime() - * Convert datetime to abstime. + * Convert timestamp to abstime. */ AbsoluteTime -datetime_abstime(DateTime *datetime) +timestamp_abstime(Timestamp *timestamp) { AbsoluteTime result; @@ -502,35 +589,35 @@ datetime_abstime(DateTime *datetime) struct tm tt, *tm = &tt; - if (!PointerIsValid(datetime)) + if (!PointerIsValid(timestamp)) { result = INVALID_ABSTIME; } - else if (DATETIME_IS_INVALID(*datetime)) + else if (TIMESTAMP_IS_INVALID(*timestamp)) { result = INVALID_ABSTIME; } - else if (DATETIME_IS_NOBEGIN(*datetime)) + else if (TIMESTAMP_IS_NOBEGIN(*timestamp)) { result = NOSTART_ABSTIME; } - else if (DATETIME_IS_NOEND(*datetime)) + else if (TIMESTAMP_IS_NOEND(*timestamp)) { result = NOEND_ABSTIME; } else { - if (DATETIME_IS_RELATIVE(*datetime)) + if (TIMESTAMP_IS_RELATIVE(*timestamp)) { - datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL); + timestamp2tm(SetTimestamp(*timestamp), NULL, tm, &fsec, NULL); result = tm2abstime(tm, 0); } - else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0) + else if (timestamp2tm(*timestamp, NULL, tm, &fsec, NULL) == 0) { result = tm2abstime(tm, 0); @@ -542,39 +629,39 @@ datetime_abstime(DateTime *datetime) }; return result; -} /* datetime_abstime() */ +} /* timestamp_abstime() */ -/* abstime_datetime() - * Convert abstime to datetime. +/* abstime_timestamp() + * Convert abstime to timestamp. */ -DateTime * -abstime_datetime(AbsoluteTime abstime) +Timestamp * +abstime_timestamp(AbsoluteTime abstime) { - DateTime *result; + Timestamp *result; - if (!PointerIsValid(result = palloc(sizeof(DateTime)))) - elog(ERROR, "Unable to allocate space to convert abstime to datetime"); + if (!PointerIsValid(result = palloc(sizeof(Timestamp)))) + elog(ERROR, "Unable to allocate space to convert abstime to timestamp"); switch (abstime) { case INVALID_ABSTIME: - DATETIME_INVALID(*result); + TIMESTAMP_INVALID(*result); break; case NOSTART_ABSTIME: - DATETIME_NOBEGIN(*result); + TIMESTAMP_NOBEGIN(*result); break; case NOEND_ABSTIME: - DATETIME_NOEND(*result); + TIMESTAMP_NOEND(*result); break; case EPOCH_ABSTIME: - DATETIME_EPOCH(*result); + TIMESTAMP_EPOCH(*result); break; case CURRENT_ABSTIME: - DATETIME_CURRENT(*result); + TIMESTAMP_CURRENT(*result); break; default: @@ -583,4 +670,1195 @@ abstime_datetime(AbsoluteTime abstime) }; return result; -} /* abstime_datetime() */ +} /* abstime_timestamp() */ + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* + * reltimein - converts a reltime string in an internal format + */ +RelativeTime +reltimein(char *str) +{ + RelativeTime result; + + struct tm tt, + *tm = &tt; + double fsec; + int dtype; + char *field[MAXDATEFIELDS]; + int nf, + 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); + + 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; + + default: + return INVALID_RELTIME; + } + + elog(ERROR, "Bad reltime (internal coding error) '%s'", str); + return INVALID_RELTIME; +} /* reltimein() */ + + +/* + * reltimeout - converts the internal format to a reltime string + */ +char * +reltimeout(RelativeTime time) +{ + char *result; + struct tm tt, + *tm = &tt; + char buf[MAXDATELEN + 1]; + + if (time == INVALID_RELTIME) + { + strcpy(buf, INVALID_RELTIME_STR); + + } + else + { + reltime2tm(time, tm); + EncodeTimeSpan(tm, 0, DateStyle, buf); + } + + result = palloc(strlen(buf) + 1); + strcpy(result, buf); + + return result; +} /* reltimeout() */ + + +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() */ + +#ifdef NOT_USED +int +dummyfunc() +{ + 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; +} + +#endif + + +/* + * tintervalin - converts an interval string to an internal format + */ +TimeInterval +tintervalin(char *intervalstr) +{ + 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; +} + + +/* + * tintervalout - converts an internal interval format to a string + * + */ +char * +tintervalout(TimeInterval interval) +{ + 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 * + *****************************************************************************/ + +RelativeTime +interval_reltime(Interval *interval) +{ + RelativeTime time; + int year, + month; + double span; + + if (!PointerIsValid(interval)) + time = INVALID_RELTIME; + + if (INTERVAL_IS_INVALID(*interval)) + { + time = INVALID_RELTIME; + + } + else + { + if (interval->month == 0) + { + year = 0; + month = 0; + + } + else if (abs(interval->month) >= 12) + { + year = (interval->month / 12); + month = (interval->month % 12); + + } + else + { + year = 0; + month = interval->month; + } + + span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time); + + time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME); + } + + return time; +} /* interval_reltime() */ + + +Interval * +reltime_interval(RelativeTime reltime) +{ + Interval *result; + int year, + month; + + if (!PointerIsValid(result = palloc(sizeof(Interval)))) + elog(ERROR, "Memory allocation failed, can't convert reltime to interval"); + + switch (reltime) + { + case INVALID_RELTIME: + INTERVAL_INVALID(*result); + break; + + default: + TMODULO(reltime, year, 31536000); + TMODULO(reltime, month, 2592000); + + result->time = reltime; + result->month = ((12 * year) + month); + } + + return result; +} /* reltime_interval() */ + + +/* + * mktinterval - creates a time interval with endpoints t1 and t2 + */ +TimeInterval +mktinterval(AbsoluteTime t1, AbsoluteTime t2) +{ + AbsoluteTime tstart = ABSTIMEMIN(t1, t2), + tend = ABSTIMEMAX(t1, t2); + TimeInterval interval; + + 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; + } + + return interval; +} + +/* + * timepl, timemi and abstimemi use the formula + * abstime + reltime = abstime + * so abstime - reltime = abstime + * and abstime - abstime = reltime + */ + +/* + * timepl - returns the value of (abstime t1 + relime t2) + */ +AbsoluteTime +timepl(AbsoluteTime t1, RelativeTime t2) +{ + 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 INVALID_ABSTIME; +} + + +/* + * timemi - returns the value of (abstime t1 - reltime t2) + */ +AbsoluteTime +timemi(AbsoluteTime t1, RelativeTime t2) +{ + 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; +} + + +/* + * abstimemi - returns the value of (abstime t1 - abstime t2) + */ +static RelativeTime +abstimemi(AbsoluteTime t1, AbsoluteTime t2) +{ + if (t1 == CURRENT_ABSTIME) + t1 = GetCurrentTransactionStartTime(); + if (t2 == CURRENT_ABSTIME) + t2 = GetCurrentTransactionStartTime(); + + if (AbsoluteTimeIsReal(t1) && + AbsoluteTimeIsReal(t2)) + return t1 - t2; + + return INVALID_RELTIME; +} + + +/* + * intinterval - returns 1, iff absolute date is in the interval + */ +int +intinterval(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; +} + +/* + * tintervalrel - returns relative time corresponding to interval + */ +RelativeTime +tintervalrel(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 + */ +AbsoluteTime +timenow() +{ + time_t sec; + + if (time(&sec) < 0) + return INVALID_ABSTIME; + return (AbsoluteTime) sec; +} + +/* + * 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; +} + +bool +reltimene(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 != t2; +} + +bool +reltimelt(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 < t2; +} + +bool +reltimegt(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 > t2; +} + +bool +reltimele(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 <= t2; +} + +bool +reltimege(RelativeTime t1, RelativeTime t2) +{ + if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME) + return 0; + return t1 >= t2; +} + + +/* + * tintervalsame - returns 1, iff interval i1 is same as interval i2 + * Check begin and end time. + */ +bool +tintervalsame(TimeInterval i1, TimeInterval i2) +{ + 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])); +} /* tintervalsame() */ + + +/* + * tintervaleq - returns 1, iff interval i1 is equal to interval i2 + * Check length of intervals. + */ +bool +tintervaleq(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervaleq() */ + +/* + * tintervalne - returns 1, iff interval i1 is not equal to interval i2 + * Check length of intervals. + */ +bool +tintervalne(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervalne() */ + +/* + * tintervallt - returns TRUE, iff interval i1 is less than interval i2 + * Check length of intervals. + */ +bool +tintervallt(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervallt() */ + +/* + * tintervalle - returns TRUE, iff interval i1 is less than or equal to interval i2 + * Check length of intervals. + */ +bool +tintervalle(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervalle() */ + +/* + * tintervalgt - returns TRUE, iff interval i1 is less than interval i2 + * Check length of intervals. + */ +bool +tintervalgt(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervalgt() */ + +/* + * tintervalge - returns TRUE, iff interval i1 is less than or equal to interval i2 + * Check length of intervals. + */ +bool +tintervalge(TimeInterval i1, TimeInterval i2) +{ + AbsoluteTime t10, + t11, + t20, + t21; + + if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) + return FALSE; /* invalid interval */ + + 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; + + 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); +} /* tintervalge() */ + + +/* + * tintervalleneq - returns 1, iff length of interval i is equal to + * reltime t + */ +bool +tintervalleneq(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt == t; +} + +/* + * tintervallenne - returns 1, iff length of interval i is not equal + * to reltime t + */ +bool +tintervallenne(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt != t; +} + +/* + * tintervallenlt - returns 1, iff length of interval i is less than + * reltime t + */ +bool +tintervallenlt(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt < t; +} + +/* + * tintervallengt - returns 1, iff length of interval i is greater than + * reltime t + */ +bool +tintervallengt(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt > t; +} + +/* + * tintervallenle - returns 1, iff length of interval i is less or equal + * than reltime t + */ +bool +tintervallenle(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt <= t; +} + +/* + * tintervallenge - returns 1, iff length of interval i is greater or + * equal than reltime t + */ +bool +tintervallenge(TimeInterval i, RelativeTime t) +{ + RelativeTime rt; + + if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME)) + return 0; + rt = tintervalrel(i); + return rt != INVALID_RELTIME && rt >= t; +} + +/* + * tintervalct - returns 1, iff interval i1 contains interval i2 + */ +bool +tintervalct(TimeInterval i1, TimeInterval i2) +{ + 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])); +} + +/* + * tintervalov - returns 1, iff interval i1 (partially) overlaps i2 + */ +bool +tintervalov(TimeInterval i1, TimeInterval i2) +{ + 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]))); +} + +/* + * tintervalstart - returns the start of interval i + */ +AbsoluteTime +tintervalstart(TimeInterval i) +{ + if (i->status == T_INTERVAL_INVAL) + return INVALID_ABSTIME; + return i->data[0]; +} + +/* + * tintervalend - returns the end of interval i + */ +AbsoluteTime +tintervalend(TimeInterval i) +{ + if (i->status == T_INTERVAL_INVAL) + return INVALID_ABSTIME; + return i->data[1]; +} + + +/***************************************************************************** + * 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' + * + */ +int +isreltime(char *str) +{ + struct tm tt, + *tm = &tt; + double fsec; + int dtype; + char *field[MAXDATEFIELDS]; + int nf, + ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return 0; + + if (strlen(str) > MAXDATELEN) + return 0; + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) + return 0; + + switch (dtype) + { + case (DTK_DELTA): + return (abs(tm->tm_year) <= 68) ? 1 : 0; + break; + + case (DTK_INVALID): + return 2; + break; + + default: + return 0; + break; + } + + 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 (;;) + { + c = *p; + if (isdigit(c)) + { + *quantity = *quantity * 10 + (c - '0'); + p++; + } + else + { + if (c == ' ') + break; /* correct quantity found */ + else + return 0; /* syntax error */ + } + } + + /* 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 (;;) + { + 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 */ + } + } + + return 1; +} + +/* + * 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 */ +} + +/* + * 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 */ +} + +#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: + * `[' {` '} `'' `'' {` '} `'' `'' {` '} `]' + * + * OR `Undefined Range' (see also INVALID_INTERVAL_STR) + * + * where satisfies the syntax of absolute time. + * + * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970'] + */ +static int +istinterval(char *i_string, + AbsoluteTime *i_start, + AbsoluteTime *i_end) +{ + char *p, + *p1; + char c; + + p = i_string; + /* skip leading blanks up to '[' */ + while ((c = *p) != '\0') + { + if (IsSpace(c)) + p++; + else if (c != '[') + return 0; /* syntax error */ + else + break; + } + 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') + { + if (IsSpace(c)) + p++; + else if (c != ']') + return 0; /* syntax error */ + else + break; + } + p++; + c = *p; + if (c != '\0') + return 0; /* syntax error */ + /* it seems to be a valid interval */ + return 1; +} + + +/***************************************************************************** + * + *****************************************************************************/ + +int32 /* RelativeTime */ +int4reltime(int32 timevalue) +{ + return timevalue; +} + +/* + * 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; +} diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index cdbac4c7f1..77202c8308 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1,114 +1,2210 @@ -#include +/*------------------------------------------------------------------------- + * + * timestamp.c + * Functions for the built-in SQL92 type "timestamp" and "interval". + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.22 2000/02/16 17:24:48 thomas Exp $ + * + *------------------------------------------------------------------------- + */ #include +#include +#include +#include #include "postgres.h" -#include "access/xact.h" +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef USE_POSIX_TIME +#include +#endif + #include "miscadmin.h" #include "utils/builtins.h" -time_t -timestamp_in(const char *timestamp_str) -{ - int4 result; - result = nabstimein((char *) timestamp_str); +#if 0 + + +static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); +static int DecodeNumber(int flen, char *field, + int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); +static int DecodeNumberField(int len, char *str, + int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits); +static int DecodeSpecial(int field, char *lowtoken, int *val); +static int DecodeTime(char *str, int fmask, int *tmask, + struct tm * tm, double *fsec); +static int DecodeTimezone(char *str, int *tzp); +static int DecodeUnits(int field, char *lowtoken, int *val); +static int EncodeSpecialTimestamp(Timestamp dt, char *str); +static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); +static Timestamp dt2local(Timestamp dt, int timezone); +static int j2day(int jd); +static double time2t(const int hour, const int min, const double sec); +static int interval2tm(Interval span, struct tm * tm, float8 *fsec); +static int tm2interval(struct tm * tm, double fsec, Interval *span); + + +#define USE_DATE_CACHE 1 +#define ROUND_ALL 0 + +int day_tab[2][13] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, +{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}}; + + +char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", +"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; + +char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", +"Thursday", "Friday", "Saturday", NULL}; + +/* TMODULO() + * Macro to replace modf(), which is broken on some platforms. + */ +#define TMODULO(t,q,u) \ +do { \ + q = ((t < 0)? ceil(t / u): floor(t / u)); \ + if (q != 0) \ + t -= rint(q * u); \ +} while(0) + +static void GetEpochTime(struct tm * tm); + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#endif + + +static double time2t(const int hour, const int min, const double sec); + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* timestamp_in() + * Convert a string to internal form. + */ +Timestamp * +timestamp_in(char *str) +{ + Timestamp *result; + + double fsec; + struct tm tt, + *tm = &tt; + int tz; + int dtype; + int nf; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) timestamp external representation"); + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) + elog(ERROR, "Bad timestamp external representation '%s'", str); + + result = palloc(sizeof(Timestamp)); + + switch (dtype) + { + case DTK_DATE: + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "Timestamp out of range '%s'", str); + break; + + case DTK_EPOCH: + TIMESTAMP_EPOCH(*result); + break; + + case DTK_CURRENT: + TIMESTAMP_CURRENT(*result); + break; + + case DTK_LATE: + TIMESTAMP_NOEND(*result); + break; + + case DTK_EARLY: + TIMESTAMP_NOBEGIN(*result); + break; + + case DTK_INVALID: + TIMESTAMP_INVALID(*result); + break; + + default: + elog(ERROR, "Internal coding error, can't input timestamp '%s'", str); + } return result; -} +} /* timestamp_in() */ +/* timestamp_out() + * Convert a timestamp to external form. + */ char * -timestamp_out(time_t timestamp) +timestamp_out(Timestamp *dt) { char *result; int tz; - double fsec = 0; struct tm tt, *tm = &tt; + double fsec; + char *tzn; char buf[MAXDATELEN + 1]; - char zone[MAXDATELEN + 1], - *tzn = zone; - switch (timestamp) + if (!PointerIsValid(dt)) + return NULL; + + if (TIMESTAMP_IS_RESERVED(*dt)) { - case EPOCH_ABSTIME: - strcpy(buf, EPOCH); - break; - case INVALID_ABSTIME: - strcpy(buf, INVALID); - break; - case CURRENT_ABSTIME: - strcpy(buf, DCURRENT); - break; - case NOEND_ABSTIME: - strcpy(buf, LATE); - break; - case NOSTART_ABSTIME: - strcpy(buf, EARLY); - break; - default: - abstime2tm(timestamp, &tz, tm, tzn); - EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf); - break; + EncodeSpecialTimestamp(*dt, buf); + } + else if (timestamp2tm(*dt, &tz, tm, &fsec, &tzn) == 0) + { + EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); + + } + else + EncodeSpecialTimestamp(DT_INVALID, buf); result = palloc(strlen(buf) + 1); + strcpy(result, buf); + return result; } /* timestamp_out() */ -time_t + +/* interval_in() + * Convert a string to internal form. + * + * External format(s): + * Uses the generic date/time parsing and decoding routines. + */ +Interval * +interval_in(char *str) +{ + Interval *span; + + double fsec; + struct tm tt, + *tm = &tt; + int dtype; + int nf; + char *field[MAXDATEFIELDS]; + int ftype[MAXDATEFIELDS]; + char lowstr[MAXDATELEN + 1]; + + tm->tm_year = 0; + tm->tm_mon = 0; + tm->tm_mday = 0; + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + fsec = 0; + + if (!PointerIsValid(str)) + elog(ERROR, "Bad (null) interval external representation"); + + if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0)) + elog(ERROR, "Bad interval external representation '%s'", str); + + span = palloc(sizeof(Interval)); + + switch (dtype) + { + case DTK_DELTA: + if (tm2interval(tm, fsec, span) != 0) + { +#if NOT_USED + INTERVAL_INVALID(span); +#endif + elog(ERROR, "Bad interval external representation '%s'", str); + } + break; + + default: + elog(ERROR, "Internal coding error, can't input interval '%s'", str); + } + + return span; +} /* interval_in() */ + +/* interval_out() + * Convert a time span to external form. + */ +char * +interval_out(Interval *span) +{ + char *result; + + struct tm tt, + *tm = &tt; + double fsec; + char buf[MAXDATELEN + 1]; + + if (!PointerIsValid(span)) + return NULL; + + if (interval2tm(*span, tm, &fsec) != 0) + return NULL; + + if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0) + elog(ERROR, "Unable to format interval"); + + result = palloc(strlen(buf) + 1); + + strcpy(result, buf); + return result; +} /* interval_out() */ + + +/* EncodeSpecialTimestamp() + * Convert reserved timestamp data type to string. + */ +int +EncodeSpecialTimestamp(Timestamp dt, char *str) +{ + if (TIMESTAMP_IS_RESERVED(dt)) + { + if (TIMESTAMP_IS_INVALID(dt)) + strcpy(str, INVALID); + else if (TIMESTAMP_IS_NOBEGIN(dt)) + strcpy(str, EARLY); + else if (TIMESTAMP_IS_NOEND(dt)) + strcpy(str, LATE); + else if (TIMESTAMP_IS_CURRENT(dt)) + strcpy(str, DCURRENT); + else if (TIMESTAMP_IS_EPOCH(dt)) + strcpy(str, EPOCH); + else + strcpy(str, INVALID); + return TRUE; + } + + return FALSE; +} /* EncodeSpecialTimestamp() */ + +Timestamp * now(void) { - time_t sec; + Timestamp *result; + AbsoluteTime sec; + + result = palloc(sizeof(Timestamp)); sec = GetCurrentTransactionStartTime(); - return sec; + + *result = (sec - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400)); + + return result; } +void +dt2time(Timestamp jd, int *hour, int *min, double *sec) +{ + double time; + + time = jd; + + *hour = (time / 3600); + time -= ((*hour) * 3600); + *min = (time / 60); + time -= ((*min) * 60); + *sec = JROUND(time); + + return; +} /* dt2time() */ + + +/* timestamp2tm() + * Convert timestamp data type to POSIX time structure. + * Note that year is _not_ 1900-based, but is an explicit full value. + * Also, month is one-based, _not_ zero-based. + * Returns: + * 0 on success + * -1 on out of range + * + * For dates within the system-supported time_t range, convert to the + * local time zone. If out of this range, leave as GMT. - tgl 97/05/27 + */ +int +timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn) +{ + double date, + date0, + time, + sec; + time_t utime; + +#ifdef USE_POSIX_TIME + struct tm *tx; + +#endif + + date0 = date2j(2000, 1, 1); + + time = dt; + TMODULO(time, date, 86400e0); + + if (time < 0) + { + time += 86400; + date -= 1; + } + + /* Julian day routine does not work for negative Julian days */ + if (date < -date0) + return -1; + + /* add offset to go from J2000 back to standard Julian date */ + date += date0; + + j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + dt2time(time, &tm->tm_hour, &tm->tm_min, &sec); + + *fsec = JROUND(sec); + TMODULO(*fsec, tm->tm_sec, 1e0); + + if (tzp != NULL) + { + if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + { + utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400); + +#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_hour = tx->tm_hour; + tm->tm_min = tx->tm_min; +#if NOT_USED +/* XXX HACK + * Argh! My Linux box puts in a 1 second offset for dates less than 1970 + * but only if the seconds field was non-zero. So, don't copy the seconds + * field and instead carry forward from the original - tgl 97/06/18 + * Note that GNU/Linux uses the standard freeware zic package as do + * many other platforms so this may not be GNU/Linux/ix86-specific. + */ + tm->tm_sec = tx->tm_sec; +#endif + tm->tm_isdst = tx->tm_isdst; + +#if defined(HAVE_TM_ZONE) + tm->tm_gmtoff = tx->tm_gmtoff; + tm->tm_zone = tx->tm_zone; + + *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ + 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 + + } + else + { + *tzp = 0; + tm->tm_isdst = 0; + if (tzn != NULL) + *tzn = NULL; + } + + dt = dt2local(dt, *tzp); + + } + else + { + tm->tm_isdst = 0; + if (tzn != NULL) + *tzn = NULL; + } + + return 0; +} /* timestamp2tm() */ + + +/* tm2timestamp() + * Convert a tm structure to a timestamp data type. + * Note that year is _not_ 1900-based, but is an explicit full value. + * Also, month is one-based, _not_ zero-based. + */ +int +tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result) +{ + + double date, + time; + + /* Julian day routines are not correct for negative Julian days */ + if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) + return -1; + + date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); + time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec)); + *result = (date * 86400 + time); + if (tzp != NULL) + *result = dt2local(*result, -(*tzp)); + + return 0; +} /* tm2timestamp() */ + + +/* interval2tm() + * Convert a interval data type to a tm structure. + */ +int +interval2tm(Interval span, struct tm * tm, float8 *fsec) +{ + double time; + + if (span.month != 0) + { + tm->tm_year = span.month / 12; + tm->tm_mon = span.month % 12; + + } + else + { + tm->tm_year = 0; + tm->tm_mon = 0; + } + +#ifdef ROUND_ALL + time = JROUND(span.time); +#else + time = span.time; +#endif + + TMODULO(time, tm->tm_mday, 86400e0); + TMODULO(time, tm->tm_hour, 3600e0); + TMODULO(time, tm->tm_min, 60e0); + TMODULO(time, tm->tm_sec, 1e0); + *fsec = time; + + return 0; +} /* interval2tm() */ + +int +tm2interval(struct tm * tm, double fsec, Interval *span) +{ + span->month = ((tm->tm_year * 12) + tm->tm_mon); + span->time = ((((((tm->tm_mday * 24.0) + + tm->tm_hour) * 60.0) + + tm->tm_min) * 60.0) + + tm->tm_sec); + span->time = JROUND(span->time + fsec); + + return 0; +} /* tm2interval() */ + +static double +time2t(const int hour, const int min, const double sec) +{ + return (((hour * 60) + min) * 60) + sec; +} /* time2t() */ + +Timestamp +dt2local(Timestamp dt, int tz) +{ + dt -= tz; + dt = JROUND(dt); + return dt; +} /* dt2local() */ + + +/***************************************************************************** + * PUBLIC ROUTINES * + *****************************************************************************/ + + bool -timestampeq(time_t t1, time_t t2) +timestamp_finite(Timestamp *timestamp) { - return abstimeeq(t1, t2); -} + if (!PointerIsValid(timestamp)) + return FALSE; + + return !TIMESTAMP_NOT_FINITE(*timestamp); +} /* timestamp_finite() */ bool -timestampne(time_t t1, time_t t2) +interval_finite(Interval *interval) { - return abstimene(t1, t2); -} + if (!PointerIsValid(interval)) + return FALSE; + + return !INTERVAL_NOT_FINITE(*interval); +} /* interval_finite() */ + + +/*---------------------------------------------------------- + * Relational operators for timestamp. + *---------------------------------------------------------*/ + +static void +GetEpochTime(struct tm * tm) +{ + struct tm *t0; + time_t epoch = 0; + + t0 = gmtime(&epoch); + + tm->tm_year = t0->tm_year; + tm->tm_mon = t0->tm_mon; + tm->tm_mday = t0->tm_mday; + tm->tm_hour = t0->tm_hour; + tm->tm_min = t0->tm_min; + tm->tm_sec = t0->tm_sec; + + if (tm->tm_year < 1900) + tm->tm_year += 1900; + tm->tm_mon++; + + return; +} /* GetEpochTime() */ + +Timestamp +SetTimestamp(Timestamp dt) +{ + struct tm tt; + + if (TIMESTAMP_IS_CURRENT(dt)) + { + GetCurrentTime(&tt); + tm2timestamp(&tt, 0, NULL, &dt); + dt = dt2local(dt, -CTimeZone); + } + else + { /* if (TIMESTAMP_IS_EPOCH(dt1)) */ + GetEpochTime(&tt); + tm2timestamp(&tt, 0, NULL, &dt); + } + + return dt; +} /* SetTimestamp() */ + +/* timestamp_relop - is timestamp1 relop timestamp2 + */ +bool +timestamp_eq(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 == dt2; +} /* timestamp_eq() */ bool -timestamplt(time_t t1, time_t t2) +timestamp_ne(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimelt(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 != dt2; +} /* timestamp_ne() */ bool -timestampgt(time_t t1, time_t t2) +timestamp_lt(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimegt(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 < dt2; +} /* timestamp_lt() */ bool -timestample(time_t t1, time_t t2) +timestamp_gt(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimele(t1, t2); -} + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 > dt2; +} /* timestamp_gt() */ bool -timestampge(time_t t1, time_t t2) +timestamp_le(Timestamp *timestamp1, Timestamp *timestamp2) { - return abstimege(t1, t2); -} + Timestamp dt1, + dt2; -DateTime * -timestamp_datetime(time_t timestamp) -{ - return abstime_datetime((AbsoluteTime) timestamp); -} /* timestamp_datetime() */ + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; -time_t -datetime_timestamp(DateTime *datetime) + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 <= dt2; +} /* timestamp_le() */ + +bool +timestamp_ge(Timestamp *timestamp1, Timestamp *timestamp2) { - return (AbsoluteTime) datetime_abstime(datetime); -} /* datetime_timestamp() */ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return FALSE; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2)) + return FALSE; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + return dt1 >= dt2; +} /* timestamp_ge() */ + + +/* timestamp_cmp - 3-state comparison for timestamp + * collate invalid timestamp at the end + */ +int +timestamp_cmp(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return 0; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_INVALID(dt1)) + { + return (TIMESTAMP_IS_INVALID(dt2) ? 0 : 1); + + } + else if (TIMESTAMP_IS_INVALID(dt2)) + { + return -1; + + } + else + { + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + } + + return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0)); +} /* timestamp_cmp() */ + + +/* interval_relop - is interval1 relop interval2 + */ +bool +interval_eq(Interval *interval1, Interval *interval2) +{ + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + return ((interval1->time == interval2->time) + && (interval1->month == interval2->month)); +} /* interval_eq() */ + +bool +interval_ne(Interval *interval1, Interval *interval2) +{ + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + return ((interval1->time != interval2->time) + || (interval1->month != interval2->month)); +} /* interval_ne() */ + +bool +interval_lt(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 < span2; +} /* interval_lt() */ + +bool +interval_gt(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 > span2; +} /* interval_gt() */ + +bool +interval_le(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 <= span2; +} /* interval_le() */ + +bool +interval_ge(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return FALSE; + + if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2)) + return FALSE; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return span1 >= span2; +} /* interval_ge() */ + + +/* interval_cmp - 3-state comparison for interval + */ +int +interval_cmp(Interval *interval1, Interval *interval2) +{ + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return 0; + + if (INTERVAL_IS_INVALID(*interval1)) + { + return INTERVAL_IS_INVALID(*interval2) ? 0 : 1; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + return -1; + + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + return (span1 < span2) ? -1 : (span1 > span2) ? 1 : 0; +} /* interval_cmp() */ + + +/*---------------------------------------------------------- + * "Arithmetic" operators on date/times. + * timestamp_foo returns foo as an object (pointer) that + * can be passed between languages. + * timestamp_xx is an internal routine which returns the + * actual value. + *---------------------------------------------------------*/ + +Timestamp * +timestamp_smaller(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1)) + *result = dt2; + else if (TIMESTAMP_IS_INVALID(dt2)) + *result = dt1; + else + *result = ((dt2 < dt1) ? dt2 : dt1); + + return result; +} /* timestamp_smaller() */ + +Timestamp * +timestamp_larger(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Timestamp *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1)) + *result = dt2; + else if (TIMESTAMP_IS_INVALID(dt2)) + *result = dt1; + else + *result = ((dt2 > dt1) ? dt2 : dt1); + + return result; +} /* timestamp_larger() */ + + +Interval * +timestamp_mi(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Interval *result; + + Timestamp dt1, + dt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + dt1 = *timestamp1; + dt2 = *timestamp2; + + result = palloc(sizeof(Interval)); + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1) + || TIMESTAMP_IS_INVALID(dt2)) + { + TIMESTAMP_INVALID(result->time); + + } + else + result->time = JROUND(dt1 - dt2); + result->month = 0; + + return result; +} /* timestamp_mi() */ + + +/* timestamp_pl_span() + * Add a interval to a timestamp data type. + * Note that interval has provisions for qualitative year/month + * units, so try to do the right thing with them. + * To add a month, increment the month, and use the same day of month. + * Then, if the next month has fewer days, set the day of month + * to the last day of month. + * Lastly, add in the "quantitative time". + */ +Timestamp * +timestamp_pl_span(Timestamp *timestamp, Interval *span) +{ + Timestamp *result; + Timestamp dt; + int tz; + char *tzn; + + if ((!PointerIsValid(timestamp)) || (!PointerIsValid(span))) + return NULL; + + result = palloc(sizeof(Timestamp)); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { + *result = *timestamp; + + } + else if (INTERVAL_IS_INVALID(*span)) + { + TIMESTAMP_INVALID(*result); + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if (span->month != 0) + { + struct tm tt, + *tm = &tt; + double fsec; + + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0) + { + tm->tm_mon += span->month; + if (tm->tm_mon > 12) + { + tm->tm_year += ((tm->tm_mon - 1) / 12); + tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1); + } + else if (tm->tm_mon < 1) + { + tm->tm_year += ((tm->tm_mon / 12) - 1); + tm->tm_mon = ((tm->tm_mon % 12) + 12); + } + + /* adjust for end of month boundary problems... */ + if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) + tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); + + if (tm2timestamp(tm, fsec, &tz, &dt) != 0) + elog(ERROR, "Unable to add timestamp and interval"); + + } + else + TIMESTAMP_INVALID(dt); + } + +#ifdef ROUND_ALL + dt = JROUND(dt + span->time); +#else + dt += span->time; +#endif + + *result = dt; + } + + return result; +} /* timestamp_pl_span() */ + +Timestamp * +timestamp_mi_span(Timestamp *timestamp, Interval *span) +{ + Timestamp *result; + Interval tspan; + + if (!PointerIsValid(timestamp) || !PointerIsValid(span)) + return NULL; + + tspan.month = -span->month; + tspan.time = -span->time; + + result = timestamp_pl_span(timestamp, &tspan); + + return result; +} /* timestamp_mi_span() */ + + +Interval * +interval_um(Interval *interval) +{ + Interval *result; + + if (!PointerIsValid(interval)) + return NULL; + + result = palloc(sizeof(Interval)); + + result->time = -(interval->time); + result->month = -(interval->month); + + return result; +} /* interval_um() */ + + +Interval * +interval_smaller(Interval *interval1, Interval *interval2) +{ + Interval *result; + + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return NULL; + + result = palloc(sizeof(Interval)); + + if (INTERVAL_IS_INVALID(*interval1)) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + { + result->time = interval1->time; + result->month = interval1->month; + + } + else + { + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + if (span2 < span1) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else + { + result->time = interval1->time; + result->month = interval1->month; + } + } + + return result; +} /* interval_smaller() */ + +Interval * +interval_larger(Interval *interval1, Interval *interval2) +{ + Interval *result; + + double span1, + span2; + + if (!PointerIsValid(interval1) || !PointerIsValid(interval2)) + return NULL; + + result = palloc(sizeof(Interval)); + + if (INTERVAL_IS_INVALID(*interval1)) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else if (INTERVAL_IS_INVALID(*interval2)) + { + result->time = interval1->time; + result->month = interval1->month; + + } + else + { + span1 = interval1->time; + if (interval1->month != 0) + span1 += (interval1->month * (30.0 * 86400)); + span2 = interval2->time; + if (interval2->month != 0) + span2 += (interval2->month * (30.0 * 86400)); + + if (span2 > span1) + { + result->time = interval2->time; + result->month = interval2->month; + + } + else + { + result->time = interval1->time; + result->month = interval1->month; + } + } + + return result; +} /* interval_larger() */ + + +Interval * +interval_pl(Interval *span1, Interval *span2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) + return NULL; + + result = palloc(sizeof(Interval)); + + result->month = (span1->month + span2->month); + result->time = JROUND(span1->time + span2->time); + + return result; +} /* interval_pl() */ + +Interval * +interval_mi(Interval *span1, Interval *span2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(span2))) + return NULL; + + result = palloc(sizeof(Interval)); + + result->month = (span1->month - span2->month); + result->time = JROUND(span1->time - span2->time); + + return result; +} /* interval_mi() */ + +Interval * +interval_div(Interval *span1, float8 *arg2) +{ + Interval *result; + + if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2))) + return NULL; + + if (!PointerIsValid(result = palloc(sizeof(Interval)))) + elog(ERROR, "Memory allocation failed, can't divide intervals"); + + if (*arg2 == 0.0) + elog(ERROR, "interval_div: divide by 0.0 error"); + + result->month = rint(span1->month / *arg2); + result->time = JROUND(span1->time / *arg2); + + return result; +} /* interval_div() */ + +/* timestamp_age() + * Calculate time difference while retaining year/month fields. + * Note that this does not result in an accurate absolute time span + * since year and month are out of context once the arithmetic + * is done. + */ +Interval * +timestamp_age(Timestamp *timestamp1, Timestamp *timestamp2) +{ + Interval *result; + + Timestamp dt1, + dt2; + double fsec, + fsec1, + fsec2; + struct tm tt, + *tm = &tt; + struct tm tt1, + *tm1 = &tt1; + struct tm tt2, + *tm2 = &tt2; + + if (!PointerIsValid(timestamp1) || !PointerIsValid(timestamp2)) + return NULL; + + result = palloc(sizeof(Interval)); + + dt1 = *timestamp1; + dt2 = *timestamp2; + + if (TIMESTAMP_IS_RELATIVE(dt1)) + dt1 = SetTimestamp(dt1); + if (TIMESTAMP_IS_RELATIVE(dt2)) + dt2 = SetTimestamp(dt2); + + if (TIMESTAMP_IS_INVALID(dt1) + || TIMESTAMP_IS_INVALID(dt2)) + { + TIMESTAMP_INVALID(result->time); + + } + else if ((timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0) + && (timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)) + { + fsec = (fsec1 - fsec2); + tm->tm_sec = (tm1->tm_sec - tm2->tm_sec); + tm->tm_min = (tm1->tm_min - tm2->tm_min); + tm->tm_hour = (tm1->tm_hour - tm2->tm_hour); + tm->tm_mday = (tm1->tm_mday - tm2->tm_mday); + tm->tm_mon = (tm1->tm_mon - tm2->tm_mon); + tm->tm_year = (tm1->tm_year - tm2->tm_year); + + /* flip sign if necessary... */ + if (dt1 < dt2) + { + fsec = -fsec; + tm->tm_sec = -tm->tm_sec; + tm->tm_min = -tm->tm_min; + tm->tm_hour = -tm->tm_hour; + tm->tm_mday = -tm->tm_mday; + tm->tm_mon = -tm->tm_mon; + tm->tm_year = -tm->tm_year; + } + + if (tm->tm_sec < 0) + { + tm->tm_sec += 60; + tm->tm_min--; + } + + if (tm->tm_min < 0) + { + tm->tm_min += 60; + tm->tm_hour--; + } + + if (tm->tm_hour < 0) + { + tm->tm_hour += 24; + tm->tm_mday--; + } + + if (tm->tm_mday < 0) + { + if (dt1 < dt2) + { + tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1]; + tm->tm_mon--; + } + else + { + tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1]; + tm->tm_mon--; + } + } + + if (tm->tm_mon < 0) + { + tm->tm_mon += 12; + tm->tm_year--; + } + + /* recover sign if necessary... */ + if (dt1 < dt2) + { + fsec = -fsec; + tm->tm_sec = -tm->tm_sec; + tm->tm_min = -tm->tm_min; + tm->tm_hour = -tm->tm_hour; + tm->tm_mday = -tm->tm_mday; + tm->tm_mon = -tm->tm_mon; + tm->tm_year = -tm->tm_year; + } + + if (tm2interval(tm, fsec, result) != 0) + elog(ERROR, "Unable to decode timestamp"); + + } + else + elog(ERROR, "Unable to decode timestamp"); + + return result; +} /* timestamp_age() */ + + +/*---------------------------------------------------------- + * Conversion operators. + *---------------------------------------------------------*/ + + +/* timestamp_text() + * Convert timestamp to text data type. + */ +text * +timestamp_text(Timestamp *timestamp) +{ + text *result; + char *str; + int len; + + if (!PointerIsValid(timestamp)) + return NULL; + + str = timestamp_out(timestamp); + + if (!PointerIsValid(str)) + return NULL; + + len = (strlen(str) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), str, (len - VARHDRSZ)); + + pfree(str); + + return result; +} /* timestamp_text() */ + + +/* text_timestamp() + * Convert text string to timestamp. + * Text type is not null terminated, so use temporary string + * then call the standard input routine. + */ +Timestamp * +text_timestamp(text *str) +{ + Timestamp *result; + int i; + char *sp, + *dp, + dstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return NULL; + + sp = VARDATA(str); + dp = dstr; + for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) + *dp++ = *sp++; + *dp = '\0'; + + result = timestamp_in(dstr); + + return result; +} /* text_timestamp() */ + + +/* interval_text() + * Convert interval to text data type. + */ +text * +interval_text(Interval *interval) +{ + text *result; + char *str; + int len; + + if (!PointerIsValid(interval)) + return NULL; + + str = interval_out(interval); + + if (!PointerIsValid(str)) + return NULL; + + len = (strlen(str) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), str, (len - VARHDRSZ)); + + pfree(str); + + return result; +} /* interval_text() */ + + +/* text_interval() + * Convert text string to interval. + * Text type may not be null terminated, so copy to temporary string + * then call the standard input routine. + */ +Interval * +text_interval(text *str) +{ + Interval *result; + int i; + char *sp, + *dp, + dstr[MAXDATELEN + 1]; + + if (!PointerIsValid(str)) + return NULL; + + sp = VARDATA(str); + dp = dstr; + for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) + *dp++ = *sp++; + *dp = '\0'; + + result = interval_in(dstr); + + return result; +} /* text_interval() */ + +/* timestamp_trunc() + * Extract specified field from timestamp. + */ +Timestamp * +timestamp_trunc(text *units, Timestamp *timestamp) +{ + Timestamp *result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + char *tzn; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(timestamp))) + return NULL; + + result = palloc(sizeof(Timestamp)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { +#if NOT_USED +/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ + elog(ERROR, "Timestamp is not finite", NULL); +#endif + *result = 0; + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)) + { + switch (val) + { + case DTK_MILLENIUM: + tm->tm_year = (tm->tm_year / 1000) * 1000; + case DTK_CENTURY: + tm->tm_year = (tm->tm_year / 100) * 100; + case DTK_DECADE: + tm->tm_year = (tm->tm_year / 10) * 10; + case DTK_YEAR: + tm->tm_mon = 1; + case DTK_QUARTER: + tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1; + case DTK_MONTH: + tm->tm_mday = 1; + case DTK_DAY: + tm->tm_hour = 0; + case DTK_HOUR: + tm->tm_min = 0; + case DTK_MINUTE: + tm->tm_sec = 0; + case DTK_SECOND: + fsec = 0; + break; + + case DTK_MILLISEC: + fsec = rint(fsec * 1000) / 1000; + break; + + case DTK_MICROSEC: + fsec = rint(fsec * 1000000) / 1000000; + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + result = NULL; + } + + if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) + { +#ifdef USE_POSIX_TIME + tm->tm_isdst = -1; + tm->tm_year -= 1900; + tm->tm_mon -= 1; + tm->tm_isdst = -1; + mktime(tm); + tm->tm_year += 1900; + tm->tm_mon += 1; + +#if defined(HAVE_TM_ZONE) + tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ +#elif defined(HAVE_INT_TIMEZONE) + +#ifdef __CYGWIN__ + tz = (tm->tm_isdst ? (_timezone - 3600) : _timezone); +#else + tz = (tm->tm_isdst ? (timezone - 3600) : timezone); +#endif + +#else +#error USE_POSIX_TIME is defined but neither HAVE_TM_ZONE or HAVE_INT_TIMEZONE are defined +#endif + +#else /* !USE_POSIX_TIME */ + tz = CTimeZone; +#endif + } + else + { + tm->tm_isdst = 0; + tz = 0; + } + + if (tm2timestamp(tm, fsec, &tz, result) != 0) + elog(ERROR, "Unable to truncate timestamp to '%s'", lowunits); + +#if NOT_USED + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + TIMESTAMP_EPOCH(*result); + *result = dt - SetTimestamp(*result); +#endif + + } + else + { + elog(ERROR, "Timestamp units '%s' not recognized", lowunits); + result = NULL; + } + } + + return result; +} /* timestamp_trunc() */ + +/* interval_trunc() + * Extract specified field from interval. + */ +Interval * +interval_trunc(text *units, Interval *interval) +{ + Interval *result; + + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(interval))) + return NULL; + + result = palloc(sizeof(Interval)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + + if (INTERVAL_IS_INVALID(*interval)) + { +#if NOT_USED + elog(ERROR, "Interval is not finite", NULL); +#endif + result = NULL; + + } + else if (type == UNITS) + { + + if (interval2tm(*interval, tm, &fsec) == 0) + { + switch (val) + { + case DTK_MILLENIUM: + tm->tm_year = (tm->tm_year / 1000) * 1000; + case DTK_CENTURY: + tm->tm_year = (tm->tm_year / 100) * 100; + case DTK_DECADE: + tm->tm_year = (tm->tm_year / 10) * 10; + case DTK_YEAR: + tm->tm_mon = 0; + case DTK_QUARTER: + tm->tm_mon = (3 * (tm->tm_mon / 4)); + case DTK_MONTH: + tm->tm_mday = 0; + case DTK_DAY: + tm->tm_hour = 0; + case DTK_HOUR: + tm->tm_min = 0; + case DTK_MINUTE: + tm->tm_sec = 0; + case DTK_SECOND: + fsec = 0; + break; + + case DTK_MILLISEC: + fsec = rint(fsec * 1000) / 1000; + break; + + case DTK_MICROSEC: + fsec = rint(fsec * 1000000) / 1000000; + break; + + default: + elog(ERROR, "Interval units '%s' not supported", lowunits); + result = NULL; + } + + if (tm2interval(tm, fsec, result) != 0) + elog(ERROR, "Unable to truncate interval to '%s'", lowunits); + + } + else + { + elog(NOTICE, "Interval out of range"); + result = NULL; + } + +#if NOT_USED + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + *result = interval->time; + if (interval->month != 0) + { + *result += ((365.25 * 86400) * (interval->month / 12)); + *result += ((30 * 86400) * (interval->month % 12)); + } +#endif + + } + else + { + elog(ERROR, "Interval units '%s' not recognized", textout(units)); + result = NULL; + } + + return result; +} /* interval_trunc() */ + + +/* timestamp_part() + * Extract specified field from timestamp. + */ +float64 +timestamp_part(text *units, Timestamp *timestamp) +{ + float64 result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double dummy; + double fsec; + char *tzn; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(timestamp))) + return NULL; + + result = palloc(sizeof(float64data)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + if (type == IGNORE) + type = DecodeSpecial(0, lowunits, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { +#if NOT_USED +/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */ + elog(ERROR, "Timestamp is not finite", NULL); +#endif + *result = 0; + + } + else + { + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + + if ((type == UNITS) && (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)) + { + switch (val) + { + case DTK_TZ: + *result = tz; + break; + + case DTK_TZ_MINUTE: + *result = tz / 60; + TMODULO(*result, dummy, 60e0); + break; + + case DTK_TZ_HOUR: + dummy = tz; + TMODULO(dummy, *result, 3600e0); + break; + + case DTK_MICROSEC: + *result = (fsec * 1000000); + break; + + case DTK_MILLISEC: + *result = (fsec * 1000); + break; + + case DTK_SECOND: + *result = (tm->tm_sec + fsec); + break; + + case DTK_MINUTE: + *result = tm->tm_min; + break; + + case DTK_HOUR: + *result = tm->tm_hour; + break; + + case DTK_DAY: + *result = tm->tm_mday; + break; + + case DTK_MONTH: + *result = tm->tm_mon; + break; + + case DTK_QUARTER: + *result = (tm->tm_mon / 4) + 1; + break; + + case DTK_YEAR: + *result = tm->tm_year; + break; + + case DTK_DECADE: + *result = (tm->tm_year / 10); + break; + + case DTK_CENTURY: + *result = (tm->tm_year / 100); + break; + + case DTK_MILLENIUM: + *result = (tm->tm_year / 1000); + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + *result = 0; + } + + } + else if (type == RESERV) + { + switch (val) + { + case DTK_EPOCH: + TIMESTAMP_EPOCH(*result); + *result = dt - SetTimestamp(*result); + break; + + case DTK_DOW: + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to encode timestamp"); + + *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); + break; + + case DTK_DOY: + if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) != 0) + elog(ERROR, "Unable to encode timestamp"); + + *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + - date2j(tm->tm_year, 1, 1) + 1); + break; + + default: + elog(ERROR, "Timestamp units '%s' not supported", lowunits); + *result = 0; + } + + } + else + { + elog(ERROR, "Timestamp units '%s' not recognized", lowunits); + *result = 0; + } + } + + return result; +} /* timestamp_part() */ + + +/* interval_part() + * Extract specified field from interval. + */ +float64 +interval_part(text *units, Interval *interval) +{ + float64 result; + + int type, + val; + int i; + char *up, + *lp, + lowunits[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + + if ((!PointerIsValid(units)) || (!PointerIsValid(interval))) + return NULL; + + result = palloc(sizeof(float64data)); + + up = VARDATA(units); + lp = lowunits; + for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeUnits(0, lowunits, &val); + if (type == IGNORE) + type = DecodeSpecial(0, lowunits, &val); + + if (INTERVAL_IS_INVALID(*interval)) + { +#if NOT_USED + elog(ERROR, "Interval is not finite"); +#endif + *result = 0; + + } + else if (type == UNITS) + { + + if (interval2tm(*interval, tm, &fsec) == 0) + { + switch (val) + { + case DTK_MICROSEC: + *result = (fsec * 1000000); + break; + + case DTK_MILLISEC: + *result = (fsec * 1000); + break; + + case DTK_SECOND: + *result = (tm->tm_sec + fsec); + break; + + case DTK_MINUTE: + *result = tm->tm_min; + break; + + case DTK_HOUR: + *result = tm->tm_hour; + break; + + case DTK_DAY: + *result = tm->tm_mday; + break; + + case DTK_MONTH: + *result = tm->tm_mon; + break; + + case DTK_QUARTER: + *result = (tm->tm_mon / 4) + 1; + break; + + case DTK_YEAR: + *result = tm->tm_year; + break; + + case DTK_DECADE: + *result = (tm->tm_year / 10); + break; + + case DTK_CENTURY: + *result = (tm->tm_year / 100); + break; + + case DTK_MILLENIUM: + *result = (tm->tm_year / 1000); + break; + + default: + elog(ERROR, "Interval units '%s' not yet supported", textout(units)); + result = NULL; + } + + } + else + { + elog(NOTICE, "Interval out of range"); + *result = 0; + } + + } + else if ((type == RESERV) && (val == DTK_EPOCH)) + { + *result = interval->time; + if (interval->month != 0) + { + *result += ((365.25 * 86400) * (interval->month / 12)); + *result += ((30 * 86400) * (interval->month % 12)); + } + + } + else + { + elog(ERROR, "Interval units '%s' not recognized", textout(units)); + *result = 0; + } + + return result; +} /* interval_part() */ + + +/* timestamp_zone() + * Encode timestamp type with specified time zone. + */ +text * +timestamp_zone(text *zone, Timestamp *timestamp) +{ + text *result; + + Timestamp dt; + int tz; + int type, + val; + int i; + char *up, + *lp, + lowzone[MAXDATELEN + 1]; + char *tzn, + upzone[MAXDATELEN + 1]; + double fsec; + struct tm tt, + *tm = &tt; + char buf[MAXDATELEN + 1]; + int len; + + if ((!PointerIsValid(zone)) || (!PointerIsValid(timestamp))) + return NULL; + + up = VARDATA(zone); + lp = lowzone; + for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++) + *lp++ = tolower(*up++); + *lp = '\0'; + + type = DecodeSpecial(0, lowzone, &val); + + if (TIMESTAMP_NOT_FINITE(*timestamp)) + { + + /* + * could return null but Postgres doesn't like that currently. - + * tgl 97/06/12 + */ + elog(ERROR, "Timestamp is not finite"); + result = NULL; + + } + else if ((type == TZ) || (type == DTZ)) + { + tm->tm_isdst = ((type == DTZ) ? 1 : 0); + tz = val * 60; + + dt = (TIMESTAMP_IS_RELATIVE(*timestamp) ? SetTimestamp(*timestamp) : *timestamp); + dt = dt2local(dt, tz); + + if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0) + elog(ERROR, "Timestamp not legal"); + + up = upzone; + lp = lowzone; + for (i = 0; *lp != '\0'; i++) + *up++ = toupper(*lp++); + *up = '\0'; + + tzn = upzone; + EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); + + len = (strlen(buf) + VARHDRSZ); + + result = palloc(len); + + VARSIZE(result) = len; + memmove(VARDATA(result), buf, (len - VARHDRSZ)); + + } + else + { + elog(ERROR, "Time zone '%s' not recognized", lowzone); + result = NULL; + } + + return result; +} /* timestamp_zone() */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index bf93830ca2..482b299c55 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.14 2000/02/15 20:49:23 tgl Exp $ + * $Id: catversion.h,v 1.15 2000/02/16 17:26:06 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200002151 +#define CATALOG_VERSION_NO 200002161 #endif diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 7376e3ee72..67c761e369 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_aggregate.h,v 1.22 2000/01/26 05:57:56 momjian Exp $ + * $Id: pg_aggregate.h,v 1.23 2000/02/16 17:26:06 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -95,7 +95,7 @@ DATA(insert OID = 0 ( avg PGUID int2pl int2inc int2div 21 21 21 21 _nul DATA(insert OID = 0 ( avg PGUID float4pl float4inc float4div 700 700 700 700 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID float8pl float8inc float8div 701 701 701 701 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID cash_pl float8inc cash_div_flt8 790 790 701 790 _null_ 0.0 )); -DATA(insert OID = 0 ( avg PGUID timespan_pl float8inc timespan_div 1186 1186 701 1186 _null_ 0.0 )); +DATA(insert OID = 0 ( avg PGUID interval_pl float8inc interval_div 1186 1186 701 1186 _null_ 0.0 )); DATA(insert OID = 0 ( avg PGUID numeric_add numeric_inc numeric_div 1700 1700 1700 1700 _null_ 0 )); DATA(insert OID = 0 ( sum PGUID int8pl - - 20 20 0 20 _null_ _null_ )); @@ -104,7 +104,7 @@ DATA(insert OID = 0 ( sum PGUID int2pl - - 21 21 0 21 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID float4pl - - 700 700 0 700 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID float8pl - - 701 701 0 701 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID cash_pl - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( sum PGUID timespan_pl - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( sum PGUID interval_pl - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( sum PGUID numeric_add - - 1700 1700 0 1700 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID int8larger - - 20 20 0 20 _null_ _null_ )); @@ -115,8 +115,8 @@ DATA(insert OID = 0 ( max PGUID float8larger - - 701 701 0 701 _null_ _null_ DATA(insert OID = 0 ( max PGUID int4larger - - 702 702 0 702 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID date_larger - - 1082 1082 0 1082 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID cashlarger - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( max PGUID datetime_larger - - 1184 1184 0 1184 _null_ _null_ )); -DATA(insert OID = 0 ( max PGUID timespan_larger - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( max PGUID timestamp_larger - - 1184 1184 0 1184 _null_ _null_ )); +DATA(insert OID = 0 ( max PGUID interval_larger - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID text_larger - - 25 25 0 25 _null_ _null_ )); DATA(insert OID = 0 ( max PGUID numeric_larger - - 1700 1700 0 1700 _null_ _null_ )); @@ -128,8 +128,8 @@ DATA(insert OID = 0 ( min PGUID float8smaller - - 701 701 0 701 _null_ _null DATA(insert OID = 0 ( min PGUID int4smaller - - 702 702 0 702 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID date_smaller - - 1082 1082 0 1082 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID cashsmaller - - 790 790 0 790 _null_ _null_ )); -DATA(insert OID = 0 ( min PGUID datetime_smaller - - 1184 1184 0 1184 _null_ _null_ )); -DATA(insert OID = 0 ( min PGUID timespan_smaller - - 1186 1186 0 1186 _null_ _null_ )); +DATA(insert OID = 0 ( min PGUID timestamp_smaller - - 1184 1184 0 1184 _null_ _null_ )); +DATA(insert OID = 0 ( min PGUID interval_smaller - - 1186 1186 0 1186 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID text_smaller - - 25 25 0 25 _null_ _null_ )); DATA(insert OID = 0 ( min PGUID numeric_smaller - - 1700 1700 0 1700 _null_ _null_ )); diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index f33c6894af..c036ef5eac 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_opclass.h,v 1.28 2000/02/10 19:51:45 momjian Exp $ + * $Id: pg_opclass.h,v 1.29 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -106,9 +106,9 @@ DATA(insert OID = 1115 ( time_ops 1083 )); DESCR(""); DATA(insert OID = 1181 ( name_ops 19 )); DESCR(""); -DATA(insert OID = 1312 ( datetime_ops 1184 )); +DATA(insert OID = 1312 ( timestamp_ops 1184 )); DESCR(""); -DATA(insert OID = 1313 ( timespan_ops 1186 )); +DATA(insert OID = 1313 ( interval_ops 1186 )); DESCR(""); DATA(insert OID = 810 ( macaddr_ops 829 )); DESCR(""); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index fd33b4b510..e510c621d0 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.67 2000/02/10 19:51:45 momjian Exp $ + * $Id: pg_operator.h,v 1.68 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -244,18 +244,18 @@ DATA(insert OID = 568 ( "<" PGUID 0 b t f 703 703 16 569 571 0 0 reltimelt DATA(insert OID = 569 ( ">" PGUID 0 b t f 703 703 16 568 570 0 0 reltimegt scalargtsel scalargtjoinsel )); DATA(insert OID = 570 ( "<=" PGUID 0 b t f 703 703 16 571 569 0 0 reltimele scalarltsel scalarltjoinsel )); DATA(insert OID = 571 ( ">=" PGUID 0 b t f 703 703 16 570 568 0 0 reltimege scalargtsel scalargtjoinsel )); -DATA(insert OID = 572 ( "~=" PGUID 0 b t f 704 704 16 572 0 0 0 intervalsame eqsel eqjoinsel )); -DATA(insert OID = 573 ( "<<" PGUID 0 b t f 704 704 16 0 0 0 0 intervalct - - )); -DATA(insert OID = 574 ( "&&" PGUID 0 b t f 704 704 16 0 0 0 0 intervalov - - )); -DATA(insert OID = 575 ( "#=" PGUID 0 b t f 704 703 16 0 576 0 0 intervalleneq - - )); -DATA(insert OID = 576 ( "#<>" PGUID 0 b t f 704 703 16 0 575 0 0 intervallenne - - )); -DATA(insert OID = 577 ( "#<" PGUID 0 b t f 704 703 16 0 580 0 0 intervallenlt - - )); -DATA(insert OID = 578 ( "#>" PGUID 0 b t f 704 703 16 0 579 0 0 intervallengt - - )); -DATA(insert OID = 579 ( "#<=" PGUID 0 b t f 704 703 16 0 578 0 0 intervallenle - - )); -DATA(insert OID = 580 ( "#>=" PGUID 0 b t f 704 703 16 0 577 0 0 intervallenge - - )); +DATA(insert OID = 572 ( "~=" PGUID 0 b t f 704 704 16 572 0 0 0 tintervalsame eqsel eqjoinsel )); +DATA(insert OID = 573 ( "<<" PGUID 0 b t f 704 704 16 0 0 0 0 tintervalct - - )); +DATA(insert OID = 574 ( "&&" PGUID 0 b t f 704 704 16 0 0 0 0 tintervalov - - )); +DATA(insert OID = 575 ( "#=" PGUID 0 b t f 704 703 16 0 576 0 0 tintervalleneq - - )); +DATA(insert OID = 576 ( "#<>" PGUID 0 b t f 704 703 16 0 575 0 0 tintervallenne - - )); +DATA(insert OID = 577 ( "#<" PGUID 0 b t f 704 703 16 0 580 0 0 tintervallenlt - - )); +DATA(insert OID = 578 ( "#>" PGUID 0 b t f 704 703 16 0 579 0 0 tintervallengt - - )); +DATA(insert OID = 579 ( "#<=" PGUID 0 b t f 704 703 16 0 578 0 0 tintervallenle - - )); +DATA(insert OID = 580 ( "#>=" PGUID 0 b t f 704 703 16 0 577 0 0 tintervallenge - - )); DATA(insert OID = 581 ( "+" PGUID 0 b t f 702 703 702 0 0 0 0 timepl - - )); DATA(insert OID = 582 ( "-" PGUID 0 b t f 702 703 702 0 0 0 0 timemi - - )); -DATA(insert OID = 583 ( "" PGUID 0 b t f 702 704 16 0 0 0 0 ininterval - - )); +DATA(insert OID = 583 ( "" PGUID 0 b t f 702 704 16 0 0 0 0 intinterval - - )); DATA(insert OID = 584 ( "-" PGUID 0 l t f 0 700 700 0 0 0 0 float4um - - )); DATA(insert OID = 585 ( "-" PGUID 0 l t f 0 701 701 0 0 0 0 float8um - - )); DATA(insert OID = 586 ( "+" PGUID 0 b t f 700 700 700 586 0 0 0 float4pl - - )); @@ -274,7 +274,7 @@ DATA(insert OID = 598 ( "%" PGUID 0 l t f 0 701 701 0 0 0 0 dtrunc DATA(insert OID = 599 ( "%" PGUID 0 r t f 701 0 701 0 0 0 0 dround - - )); DATA(insert OID = 1282 ( ":" PGUID 0 l t f 0 701 701 0 0 0 0 dexp - - )); DATA(insert OID = 1283 ( ";" PGUID 0 l t f 0 701 701 0 0 0 0 dlog1 - - )); -DATA(insert OID = 1284 ( "|" PGUID 0 l t f 0 704 702 0 0 0 0 intervalstart - - )); +DATA(insert OID = 1284 ( "|" PGUID 0 l t f 0 704 702 0 0 0 0 tintervalstart - - )); DATA(insert OID = 606 ( "<#>" PGUID 0 b t f 702 702 704 0 0 0 0 mktinterval - - )); DATA(insert OID = 607 ( "=" PGUID 0 b t t 26 26 16 607 608 609 609 oideq eqsel eqjoinsel )); #define MIN_OIDCMP 607 /* used by cache code */ @@ -399,12 +399,12 @@ DATA(insert OID = 807 ( "/" PGUID 0 b t f 603 600 603 0 0 0 0 box_div DATA(insert OID = 808 ( "?-" PGUID 0 b t f 600 600 16 808 0 0 0 point_horiz - - )); DATA(insert OID = 809 ( "?|" PGUID 0 b t f 600 600 16 809 0 0 0 point_vert - - )); -DATA(insert OID = 811 ( "=" PGUID 0 b t f 704 704 16 811 812 0 0 intervaleq eqsel eqjoinsel )); -DATA(insert OID = 812 ( "<>" PGUID 0 b t f 704 704 16 812 811 0 0 intervalne neqsel neqjoinsel )); -DATA(insert OID = 813 ( "<" PGUID 0 b t f 704 704 16 814 816 0 0 intervallt scalarltsel scalarltjoinsel )); -DATA(insert OID = 814 ( ">" PGUID 0 b t f 704 704 16 813 815 0 0 intervalgt scalargtsel scalargtjoinsel )); -DATA(insert OID = 815 ( "<=" PGUID 0 b t f 704 704 16 816 814 0 0 intervalle scalarltsel scalarltjoinsel )); -DATA(insert OID = 816 ( ">=" PGUID 0 b t f 704 704 16 815 813 0 0 intervalge scalargtsel scalargtjoinsel )); +DATA(insert OID = 811 ( "=" PGUID 0 b t f 704 704 16 811 812 0 0 tintervaleq eqsel eqjoinsel )); +DATA(insert OID = 812 ( "<>" PGUID 0 b t f 704 704 16 812 811 0 0 tintervalne neqsel neqjoinsel )); +DATA(insert OID = 813 ( "<" PGUID 0 b t f 704 704 16 814 816 0 0 tintervallt scalarltsel scalarltjoinsel )); +DATA(insert OID = 814 ( ">" PGUID 0 b t f 704 704 16 813 815 0 0 tintervalgt scalargtsel scalargtjoinsel )); +DATA(insert OID = 815 ( "<=" PGUID 0 b t f 704 704 16 816 814 0 0 tintervalle scalarltsel scalarltjoinsel )); +DATA(insert OID = 816 ( ">=" PGUID 0 b t f 704 704 16 815 813 0 0 tintervalge scalargtsel scalargtjoinsel )); DATA(insert OID = 843 ( "*" PGUID 0 b t f 790 700 790 845 0 0 0 cash_mul_flt4 - - )); DATA(insert OID = 844 ( "/" PGUID 0 b t f 790 700 790 0 0 0 0 cash_div_flt4 - - )); @@ -536,37 +536,30 @@ DATA(insert OID = 1234 ( "~*" PGUID 0 b t f 1042 25 16 0 1235 0 0 texticreg #define OID_BPCHAR_ICREGEXEQ_OP 1234 DATA(insert OID = 1235 ( "!~*" PGUID 0 b t f 1042 25 16 0 1234 0 0 texticregexne neqsel neqjoinsel )); -DATA(insert OID = 1300 ( "=" PGUID 0 b t t 1296 1296 16 1300 1301 1302 1302 timestampeq eqsel eqjoinsel )); -DATA(insert OID = 1301 ( "<>" PGUID 0 b t f 1296 1296 16 1301 1300 0 0 timestampne neqsel neqjoinsel )); -DATA(insert OID = 1302 ( "<" PGUID 0 b t f 1296 1296 16 1303 1305 0 0 timestamplt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1303 ( ">" PGUID 0 b t f 1296 1296 16 1302 1304 0 0 timestampgt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1304 ( "<=" PGUID 0 b t f 1296 1296 16 1305 1303 0 0 timestample scalarltsel scalarltjoinsel )); -DATA(insert OID = 1305 ( ">=" PGUID 0 b t f 1296 1296 16 1304 1302 0 0 timestampge scalargtsel scalargtjoinsel )); - -/* datetime operators */ +/* timestamp operators */ /* name, owner, prec, kind, isleft, canhash, left, right, result, com, negate, lsortop, rsortop, oprcode, operrest, oprjoin */ -DATA(insert OID = 1320 ( "=" PGUID 0 b t f 1184 1184 16 1320 1321 1322 1322 datetime_eq eqsel eqjoinsel )); -DATA(insert OID = 1321 ( "<>" PGUID 0 b t f 1184 1184 16 1321 1320 0 0 datetime_ne neqsel neqjoinsel )); -DATA(insert OID = 1322 ( "<" PGUID 0 b t f 1184 1184 16 1324 1325 0 0 datetime_lt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1323 ( "<=" PGUID 0 b t f 1184 1184 16 1325 1324 0 0 datetime_le scalarltsel scalarltjoinsel )); -DATA(insert OID = 1324 ( ">" PGUID 0 b t f 1184 1184 16 1322 1323 0 0 datetime_gt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1325 ( ">=" PGUID 0 b t f 1184 1184 16 1323 1322 0 0 datetime_ge scalargtsel scalargtjoinsel )); +DATA(insert OID = 1320 ( "=" PGUID 0 b t f 1184 1184 16 1320 1321 1322 1322 timestamp_eq eqsel eqjoinsel )); +DATA(insert OID = 1321 ( "<>" PGUID 0 b t f 1184 1184 16 1321 1320 0 0 timestamp_ne neqsel neqjoinsel )); +DATA(insert OID = 1322 ( "<" PGUID 0 b t f 1184 1184 16 1324 1325 0 0 timestamp_lt scalarltsel scalarltjoinsel )); +DATA(insert OID = 1323 ( "<=" PGUID 0 b t f 1184 1184 16 1325 1324 0 0 timestamp_le scalarltsel scalarltjoinsel )); +DATA(insert OID = 1324 ( ">" PGUID 0 b t f 1184 1184 16 1322 1323 0 0 timestamp_gt scalargtsel scalargtjoinsel )); +DATA(insert OID = 1325 ( ">=" PGUID 0 b t f 1184 1184 16 1323 1322 0 0 timestamp_ge scalargtsel scalargtjoinsel )); -DATA(insert OID = 1327 ( "+" PGUID 0 b t f 1184 1186 1184 0 0 0 0 datetime_pl_span - - )); -DATA(insert OID = 1328 ( "-" PGUID 0 b t f 1184 1184 1186 0 0 0 0 datetime_mi - - )); -DATA(insert OID = 1329 ( "-" PGUID 0 b t f 1184 1186 1184 0 0 0 0 datetime_mi_span - - )); +DATA(insert OID = 1327 ( "+" PGUID 0 b t f 1184 1186 1184 0 0 0 0 timestamp_pl_span - - )); +DATA(insert OID = 1328 ( "-" PGUID 0 b t f 1184 1184 1186 0 0 0 0 timestamp_mi - - )); +DATA(insert OID = 1329 ( "-" PGUID 0 b t f 1184 1186 1184 0 0 0 0 timestamp_mi_span - - )); -/* timespan operators */ -DATA(insert OID = 1330 ( "=" PGUID 0 b t f 1186 1186 16 1330 1331 1332 1332 timespan_eq eqsel eqjoinsel )); -DATA(insert OID = 1331 ( "<>" PGUID 0 b t f 1186 1186 16 1331 1330 0 0 timespan_ne neqsel neqjoinsel )); -DATA(insert OID = 1332 ( "<" PGUID 0 b t f 1186 1186 16 1334 1335 0 0 timespan_lt scalarltsel scalarltjoinsel )); -DATA(insert OID = 1333 ( "<=" PGUID 0 b t f 1186 1186 16 1335 1334 0 0 timespan_le scalarltsel scalarltjoinsel )); -DATA(insert OID = 1334 ( ">" PGUID 0 b t f 1186 1186 16 1332 1333 0 0 timespan_gt scalargtsel scalargtjoinsel )); -DATA(insert OID = 1335 ( ">=" PGUID 0 b t f 1186 1186 16 1333 1332 0 0 timespan_ge scalargtsel scalargtjoinsel )); +/* interval operators */ +DATA(insert OID = 1330 ( "=" PGUID 0 b t f 1186 1186 16 1330 1331 1332 1332 interval_eq eqsel eqjoinsel )); +DATA(insert OID = 1331 ( "<>" PGUID 0 b t f 1186 1186 16 1331 1330 0 0 interval_ne neqsel neqjoinsel )); +DATA(insert OID = 1332 ( "<" PGUID 0 b t f 1186 1186 16 1334 1335 0 0 interval_lt scalarltsel scalarltjoinsel )); +DATA(insert OID = 1333 ( "<=" PGUID 0 b t f 1186 1186 16 1335 1334 0 0 interval_le scalarltsel scalarltjoinsel )); +DATA(insert OID = 1334 ( ">" PGUID 0 b t f 1186 1186 16 1332 1333 0 0 interval_gt scalargtsel scalargtjoinsel )); +DATA(insert OID = 1335 ( ">=" PGUID 0 b t f 1186 1186 16 1333 1332 0 0 interval_ge scalargtsel scalargtjoinsel )); -DATA(insert OID = 1336 ( "-" PGUID 0 l t f 0 1186 1186 0 0 0 0 timespan_um - - )); -DATA(insert OID = 1337 ( "+" PGUID 0 b t f 1186 1186 1186 1337 0 0 0 timespan_pl - - )); -DATA(insert OID = 1338 ( "-" PGUID 0 b t f 1186 1186 1186 0 0 0 0 timespan_mi - - )); +DATA(insert OID = 1336 ( "-" PGUID 0 l t f 0 1186 1186 0 0 0 0 interval_um - - )); +DATA(insert OID = 1337 ( "+" PGUID 0 b t f 1186 1186 1186 1337 0 0 0 interval_pl - - )); +DATA(insert OID = 1338 ( "-" PGUID 0 b t f 1186 1186 1186 0 0 0 0 interval_mi - - )); /* additional geometric operators - thomas 97/04/18 */ DATA(insert OID = 1420 ( "@@" PGUID 0 l t f 0 718 600 0 0 0 0 circle_center - - )); @@ -626,7 +619,7 @@ DATA(insert OID = 1567 ( "##" PGUID 0 b t f 601 603 600 0 0 0 0 close_s DATA(insert OID = 1568 ( "##" PGUID 0 b t f 628 603 600 0 0 0 0 close_lb - - )); DATA(insert OID = 1577 ( "##" PGUID 0 b t f 628 601 600 0 0 0 0 close_ls - - )); DATA(insert OID = 1578 ( "##" PGUID 0 b t f 601 601 600 0 0 0 0 close_lseg - - )); -DATA(insert OID = 1585 ( "/" PGUID 0 b t f 1186 701 1186 0 0 0 0 timespan_div - - )); +DATA(insert OID = 1585 ( "/" PGUID 0 b t f 1186 701 1186 0 0 0 0 interval_div - - )); DATA(insert OID = 1586 ( "<>" PGUID 0 b t f 601 601 16 1586 1535 0 0 lseg_ne neqsel neqjoinsel )); DATA(insert OID = 1587 ( "<" PGUID 0 b t f 601 601 16 1589 1590 0 0 lseg_lt - - )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 87107b1df3..64c015fbff 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.121 2000/02/15 20:49:23 tgl Exp $ + * $Id: pg_proc.h,v 1.122 2000/02/16 17:26:07 thomas Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -517,9 +517,9 @@ DATA(insert OID = 246 ( tintervalin PGUID 11 f t f 1 f 704 "0" 100 0 0 100 DESCR("(internal)"); DATA(insert OID = 247 ( tintervalout PGUID 11 f t f 1 f 23 "0" 100 0 0 100 tintervalout - )); DESCR("(internal)"); -DATA(insert OID = 248 ( ininterval PGUID 11 f t f 2 f 16 "702 704" 100 0 0 100 ininterval - )); +DATA(insert OID = 248 ( intinterval PGUID 11 f t f 2 f 16 "702 704" 100 0 0 100 intinterval - )); DESCR("abstime in tinterval"); -DATA(insert OID = 249 ( intervalrel PGUID 11 f t f 1 f 703 "704" 100 0 0 100 intervalrel - )); +DATA(insert OID = 249 ( tintervalrel PGUID 11 f t f 1 f 703 "704" 100 0 0 100 tintervalrel - )); DESCR(""); DATA(insert OID = 250 ( timenow PGUID 11 f t f 0 f 702 "0" 100 0 0 100 timenow - )); DESCR("Current date and time"); @@ -547,27 +547,27 @@ DATA(insert OID = 261 ( reltimele PGUID 11 f t t 2 f 16 "703 703" 100 0 0 1 DESCR("less-than-or-equal"); DATA(insert OID = 262 ( reltimege PGUID 11 f t t 2 f 16 "703 703" 100 0 0 100 reltimege - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 263 ( intervalsame PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalsame - )); +DATA(insert OID = 263 ( tintervalsame PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalsame - )); DESCR("same as"); -DATA(insert OID = 264 ( intervalct PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalct - )); +DATA(insert OID = 264 ( tintervalct PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalct - )); DESCR("less-than"); -DATA(insert OID = 265 ( intervalov PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalov - )); +DATA(insert OID = 265 ( tintervalov PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalov - )); DESCR("overlaps"); -DATA(insert OID = 266 ( intervalleneq PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervalleneq - )); +DATA(insert OID = 266 ( tintervalleneq PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervalleneq - )); DESCR("length equal"); -DATA(insert OID = 267 ( intervallenne PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenne - )); +DATA(insert OID = 267 ( tintervallenne PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenne - )); DESCR("length not equal to"); -DATA(insert OID = 268 ( intervallenlt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenlt - )); +DATA(insert OID = 268 ( tintervallenlt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenlt - )); DESCR("length less-than"); -DATA(insert OID = 269 ( intervallengt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallengt - )); +DATA(insert OID = 269 ( tintervallengt PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallengt - )); DESCR("length greater-than"); -DATA(insert OID = 270 ( intervallenle PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenle - )); +DATA(insert OID = 270 ( tintervallenle PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenle - )); DESCR("length less-than-or-equal"); -DATA(insert OID = 271 ( intervallenge PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 intervallenge - )); +DATA(insert OID = 271 ( tintervallenge PGUID 11 f t f 2 f 16 "704 703" 100 0 0 100 tintervallenge - )); DESCR("length greater-than-or-equal"); -DATA(insert OID = 272 ( intervalstart PGUID 11 f t f 1 f 702 "704" 100 0 0 100 intervalstart - )); +DATA(insert OID = 272 ( tintervalstart PGUID 11 f t f 1 f 702 "704" 100 0 0 100 tintervalstart - )); DESCR("start of interval"); -DATA(insert OID = 273 ( intervalend PGUID 11 f t f 1 f 702 "704" 100 0 0 100 intervalend - )); +DATA(insert OID = 273 ( tintervalend PGUID 11 f t f 1 f 702 "704" 100 0 0 100 tintervalend - )); DESCR(""); DATA(insert OID = 274 ( timeofday PGUID 11 f t f 0 f 25 "0" 100 0 0 100 timeofday - )); DESCR("Current date and time with microseconds"); @@ -920,7 +920,7 @@ DATA(insert OID = 669 ( varchar PGUID 11 f t t 2 f 1043 "1043 23" 100 0 0 1 DESCR("truncate varchar()"); DATA(insert OID = 676 ( mktinterval PGUID 11 f t f 2 f 704 "702 702" 100 0 0 100 mktinterval - )); -DESCR("convert to interval"); +DESCR("convert to tinterval"); DATA(insert OID = 619 ( oidvectorne PGUID 11 f t t 2 f 16 "30 30" 100 0 0 100 oidvectorne - )); DESCR("less-than"); DATA(insert OID = 677 ( oidvectorlt PGUID 11 f t t 2 f 16 "30 30" 100 0 0 100 oidvectorlt - )); @@ -1052,17 +1052,17 @@ DESCR("gist(internal)"); DATA(insert OID = 782 ( gistbuild PGUID 11 f t f 9 f 23 "0" 100 0 0 100 gistbuild - )); DESCR("gist(internal)"); -DATA(insert OID = 784 ( intervaleq PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervaleq - )); +DATA(insert OID = 784 ( tintervaleq PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervaleq - )); DESCR("equal"); -DATA(insert OID = 785 ( intervalne PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalne - )); +DATA(insert OID = 785 ( tintervalne PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalne - )); DESCR("not equal"); -DATA(insert OID = 786 ( intervallt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervallt - )); +DATA(insert OID = 786 ( tintervallt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervallt - )); DESCR("less-than"); -DATA(insert OID = 787 ( intervalgt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalgt - )); +DATA(insert OID = 787 ( tintervalgt PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalgt - )); DESCR("greater-than"); -DATA(insert OID = 788 ( intervalle PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalle - )); +DATA(insert OID = 788 ( tintervalle PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalle - )); DESCR("less-than-or-equal"); -DATA(insert OID = 789 ( intervalge PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 intervalge - )); +DATA(insert OID = 789 ( tintervalge PGUID 11 f t f 2 f 16 "704 704" 100 0 0 100 tintervalge - )); DESCR("greater-than-or-equal"); /* OIDS 800 - 899 */ @@ -1397,94 +1397,92 @@ DESCR("multiply"); DATA(insert OID = 1149 ( circle_div_pt PGUID 11 f t t 2 f 718 "718 600" 100 0 0 100 circle_div_pt - )); DESCR("divide"); -DATA(insert OID = 1150 ( datetime_in PGUID 11 f t f 1 f 1184 "0" 100 0 0 100 datetime_in - )); +DATA(insert OID = 1150 ( timestamp_in PGUID 11 f t f 1 f 1184 "0" 100 0 0 100 timestamp_in - )); DESCR("(internal)"); -DATA(insert OID = 1151 ( datetime_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 datetime_out - )); +DATA(insert OID = 1151 ( timestamp_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timestamp_out - )); DESCR("(internal)"); -DATA(insert OID = 1152 ( datetime_eq PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_eq - )); +DATA(insert OID = 1152 ( timestamp_eq PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_eq - )); DESCR("equal"); -DATA(insert OID = 1153 ( datetime_ne PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_ne - )); +DATA(insert OID = 1153 ( timestamp_ne PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_ne - )); DESCR("not equal"); -DATA(insert OID = 1154 ( datetime_lt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_lt - )); +DATA(insert OID = 1154 ( timestamp_lt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_lt - )); DESCR("less-than"); -DATA(insert OID = 1155 ( datetime_le PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_le - )); +DATA(insert OID = 1155 ( timestamp_le PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_le - )); DESCR("less-than-or-equal"); -DATA(insert OID = 1156 ( datetime_ge PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_ge - )); +DATA(insert OID = 1156 ( timestamp_ge PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_ge - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 1157 ( datetime_gt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 datetime_gt - )); +DATA(insert OID = 1157 ( timestamp_gt PGUID 11 f t f 2 f 16 "1184 1184" 100 0 0 100 timestamp_gt - )); DESCR("greater-than"); -DATA(insert OID = 1158 ( datetime_finite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 datetime_finite - )); +DATA(insert OID = 1158 ( timestamp_finite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 timestamp_finite - )); DESCR(""); -DATA(insert OID = 1159 ( datetime_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 datetime_zone - )); +DATA(insert OID = 1159 ( timestamp_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 timestamp_zone - )); DESCR(""); -DATA(insert OID = 1160 ( timespan_in PGUID 11 f t f 1 f 1186 "0" 100 0 0 100 timespan_in - )); +DATA(insert OID = 1160 ( interval_in PGUID 11 f t f 1 f 1186 "0" 100 0 0 100 interval_in - )); DESCR("(internal)"); -DATA(insert OID = 1161 ( timespan_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timespan_out - )); +DATA(insert OID = 1161 ( interval_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 interval_out - )); DESCR("(internal)"); -DATA(insert OID = 1162 ( timespan_eq PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_eq - )); +DATA(insert OID = 1162 ( interval_eq PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_eq - )); DESCR("equal"); -DATA(insert OID = 1163 ( timespan_ne PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_ne - )); +DATA(insert OID = 1163 ( interval_ne PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_ne - )); DESCR("not equal"); -DATA(insert OID = 1164 ( timespan_lt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_lt - )); +DATA(insert OID = 1164 ( interval_lt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_lt - )); DESCR("less-than"); -DATA(insert OID = 1165 ( timespan_le PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_le - )); +DATA(insert OID = 1165 ( interval_le PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_le - )); DESCR("less-than-or-equal"); -DATA(insert OID = 1166 ( timespan_ge PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_ge - )); +DATA(insert OID = 1166 ( interval_ge PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_ge - )); DESCR("greater-than-or-equal"); -DATA(insert OID = 1167 ( timespan_gt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 timespan_gt - )); +DATA(insert OID = 1167 ( interval_gt PGUID 11 f t f 2 f 16 "1186 1186" 100 0 0 100 interval_gt - )); DESCR("greater-than"); -DATA(insert OID = 1168 ( timespan_um PGUID 11 f t f 1 f 1186 "1186" 100 0 0 100 timespan_um - )); +DATA(insert OID = 1168 ( interval_um PGUID 11 f t f 1 f 1186 "1186" 100 0 0 100 interval_um - )); DESCR("subtract"); -DATA(insert OID = 1169 ( timespan_pl PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_pl - )); +DATA(insert OID = 1169 ( interval_pl PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_pl - )); DESCR("addition"); -DATA(insert OID = 1170 ( timespan_mi PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_mi - )); +DATA(insert OID = 1170 ( interval_mi PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_mi - )); DESCR("subtract"); -DATA(insert OID = 1171 ( datetime_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 datetime_part - )); -DESCR("extract field from datetime"); -DATA(insert OID = 1172 ( timespan_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 timespan_part - )); -DESCR("extract field from timespan"); +DATA(insert OID = 1171 ( timestamp_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 timestamp_part - )); +DESCR("extract field from timestamp"); +DATA(insert OID = 1172 ( interval_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 interval_part - )); +DESCR("extract field from interval"); -DATA(insert OID = 1173 ( abstime_datetime PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_datetime - )); -DESCR("convert abstime to datetime"); -DATA(insert OID = 1174 ( date_datetime PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_datetime - )); -DESCR("convert date to datetime"); -DATA(insert OID = 1175 ( timestamp_datetime PGUID 11 f t f 1 f 1184 "1296" 100 0 0 100 timestamp_datetime - )); -DESCR("convert timestamp to datetime"); -DATA(insert OID = 1176 ( datetime_datetime PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_datetime - )); -DESCR("convert date and time to datetime"); -DATA(insert OID = 1177 ( reltime_timespan PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_timespan - )); -DESCR("convert reltime to timespan"); -DATA(insert OID = 1178 ( datetime_date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 datetime_date - )); -DESCR("convert datetime to date"); +DATA(insert OID = 1173 ( abstime_timestamp PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_timestamp - )); +DESCR("convert abstime to timestamp"); +DATA(insert OID = 1174 ( date_timestamp PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_timestamp - )); +DESCR("convert date to timestamp"); +DATA(insert OID = 1176 ( datetime_timestamp PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_timestamp - )); +DESCR("convert date and time to timestamp"); +DATA(insert OID = 1177 ( reltime_interval PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_interval - )); +DESCR("convert reltime to interval"); +DATA(insert OID = 1178 ( timestamp_date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 timestamp_date - )); +DESCR("convert timestamp to date"); DATA(insert OID = 1179 ( abstime_date PGUID 11 f t f 1 f 1082 "702" 100 0 0 100 abstime_date - )); DESCR("convert abstime to date"); -DATA(insert OID = 1180 ( datetime_abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 datetime_abstime - )); -DESCR("convert datetime to abstime"); +DATA(insert OID = 1180 ( timestamp_abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 timestamp_abstime - )); +DESCR("convert timestamp to abstime"); -DATA(insert OID = 1188 ( datetime_mi PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_mi - )); +DATA(insert OID = 1188 ( timestamp_mi PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_mi - )); DESCR("subtract"); -DATA(insert OID = 1189 ( datetime_pl_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 datetime_pl_span - )); +DATA(insert OID = 1189 ( timestamp_pl_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 timestamp_pl_span - )); DESCR("plus"); -DATA(insert OID = 1190 ( datetime_mi_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 datetime_mi_span - )); +DATA(insert OID = 1190 ( timestamp_mi_span PGUID 11 f t f 2 f 1184 "1184 1186" 100 0 0 100 timestamp_mi_span - )); DESCR("minus"); -DATA(insert OID = 1191 ( text_datetime PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1192 ( datetime_text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 datetime_text - )); -DESCR("convert datetime to text"); -DATA(insert OID = 1193 ( timespan_text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 timespan_text - )); -DESCR("convert timespan to text"); -DATA(insert OID = 1194 ( timespan_reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 timespan_reltime - )); -DESCR("convert timespan to reltime"); -DATA(insert OID = 1195 ( datetime_smaller PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 datetime_smaller - )); +DATA(insert OID = 1191 ( text_timestamp PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_timestamp - )); +DESCR("convert text to timestamp"); +DATA(insert OID = 1192 ( timestamp_text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 timestamp_text - )); +DESCR("convert timestamp to text"); +DATA(insert OID = 1193 ( interval_text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 interval_text - )); +DESCR("convert interval to text"); +DATA(insert OID = 1194 ( interval_reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 interval_reltime - )); +DESCR("convert interval to reltime"); +DATA(insert OID = 1195 ( timestamp_smaller PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 timestamp_smaller - )); DESCR("smaller of two"); -DATA(insert OID = 1196 ( datetime_larger PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 datetime_larger - )); +DATA(insert OID = 1196 ( timestamp_larger PGUID 11 f t f 2 f 1184 "1184 1184" 100 0 0 100 timestamp_larger - )); DESCR("larger of two"); -DATA(insert OID = 1197 ( timespan_smaller PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_smaller - )); +DATA(insert OID = 1197 ( interval_smaller PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_smaller - )); DESCR("smaller of two"); -DATA(insert OID = 1198 ( timespan_larger PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 timespan_larger - )); +DATA(insert OID = 1198 ( interval_larger PGUID 11 f t f 2 f 1186 "1186 1186" 100 0 0 100 interval_larger - )); DESCR("larger of two"); -DATA(insert OID = 1199 ( datetime_age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_age - )); +DATA(insert OID = 1199 ( timestamp_age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_age - )); DESCR("date difference preserving months and years"); /* OIDS 1200 - 1299 */ @@ -1492,10 +1490,10 @@ DESCR("date difference preserving months and years"); DATA(insert OID = 1200 ( int4reltime PGUID 11 f t t 1 f 703 "23" 100 0 0 100 int4reltime - )); DESCR("convert int4 to reltime"); -DATA(insert OID = 1217 ( datetime_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 datetime_trunc - )); -DESCR("truncate datetime to specified units"); -DATA(insert OID = 1218 ( timespan_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 timespan_trunc - )); -DESCR("truncate timespan to specified units"); +DATA(insert OID = 1217 ( timestamp_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 timestamp_trunc - )); +DESCR("truncate timestamp to specified units"); +DATA(insert OID = 1218 ( interval_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 interval_trunc - )); +DESCR("truncate interval to specified units"); DATA(insert OID = 1230 ( bpchar PGUID 11 f t t 1 f 1042 "18" 100 0 0 100 char_bpchar - )); DESCR("convert char to char()"); @@ -1523,9 +1521,9 @@ DESCR("character length"); DATA(insert OID = 1379 ( varcharoctetlen PGUID 11 f t t 1 f 23 "1043" 100 0 0 100 varcharoctetlen - )); DESCR("octet length"); -DATA(insert OID = 1263 ( text_timespan PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_timespan - )); -DESCR("convert text to timespan"); -DATA(insert OID = 1271 ( timespan_finite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 timespan_finite - )); +DATA(insert OID = 1263 ( text_interval PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_interval - )); +DESCR("convert text to interval"); +DATA(insert OID = 1271 ( interval_finite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 interval_finite - )); DESCR("boolean test"); DATA(insert OID = 1274 ( int84pl PGUID 11 f t t 2 f 20 "20 23" 100 0 0 100 int84pl - )); @@ -1562,44 +1560,26 @@ DESCR("latest tid of a tuple"); DATA(insert OID = 1294 ( currtid2 PGUID 11 f t f 2 f 27 "25 27" 100 0 0 100 currtid_byrelname - )); DESCR("latest tid of a tuple"); -DATA(insert OID = 1297 ( timestamp_in PGUID 11 f t f 1 f 1296 "0" 100 0 0 100 timestamp_in - )); -DESCR("(internal)"); -DATA(insert OID = 1298 ( timestamp_out PGUID 11 f t f 1 f 23 "0" 100 0 0 100 timestamp_out - )); -DESCR("(internal)"); -DATA(insert OID = 1299 ( now PGUID 11 f t f 0 f 1296 "0" 100 0 0 100 now - )); +DATA(insert OID = 1299 ( now PGUID 11 f t f 0 f 1184 "0" 100 0 0 100 now - )); DESCR("current transaction time"); /* OIDS 1300 - 1399 */ -DATA(insert OID = 1306 ( timestampeq PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampeq - )); -DESCR("equal"); -DATA(insert OID = 1307 ( timestampne PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampne - )); -DESCR("not equal"); -DATA(insert OID = 1308 ( timestamplt PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestamplt - )); -DESCR("less-than"); -DATA(insert OID = 1309 ( timestampgt PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampgt - )); -DESCR("greater-than"); -DATA(insert OID = 1310 ( timestample PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestample - )); -DESCR("less-than-or-equal"); -DATA(insert OID = 1311 ( timestampge PGUID 11 f t t 2 f 16 "1296 1296" 100 0 0 100 timestampge - )); -DESCR("greater-than-or-equal"); -DATA(insert OID = 1314 ( datetime_cmp PGUID 11 f t f 2 f 23 "1184 1184" 100 0 0 100 datetime_cmp - )); +DATA(insert OID = 1314 ( timestamp_cmp PGUID 11 f t f 2 f 23 "1184 1184" 100 0 0 100 timestamp_cmp - )); DESCR("less-equal-greater"); -DATA(insert OID = 1315 ( timespan_cmp PGUID 11 f t f 2 f 23 "1186 1186" 100 0 0 100 timespan_cmp - )); +DATA(insert OID = 1315 ( interval_cmp PGUID 11 f t f 2 f 23 "1186 1186" 100 0 0 100 interval_cmp - )); DESCR("less-equal-greater"); -DATA(insert OID = 1316 ( datetime_time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 datetime_time - )); -DESCR("convert datetime to time"); -DATA(insert OID = 1318 ( datetime_timestamp PGUID 11 f t f 1 f 1296 "1184" 100 0 0 100 datetime_timestamp - )); -DESCR("convert datetime to timestamp"); -DATA(insert OID = 1326 ( timespan_div PGUID 11 f t f 2 f 1186 "1186 701" 100 0 0 100 timespan_div - )); +DATA(insert OID = 1316 ( timestamp_time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 timestamp_time - )); +DESCR("convert timestamp to time"); +DATA(insert OID = 1326 ( interval_div PGUID 11 f t f 2 f 1186 "1186 701" 100 0 0 100 interval_div - )); DESCR("divide"); -DATA(insert OID = 1339 ( date_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 datetime_zone - )); +DATA(insert OID = 1339 ( date_zone PGUID 11 f t f 2 f 25 "25 1184" 100 0 0 100 timestamp_zone - )); DESCR(""); -DATA(insert OID = 1340 ( text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 datetime_text - )); -DESCR("convert datetime to text"); -DATA(insert OID = 1341 ( text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 timespan_text - )); -DESCR("convert timespan to text"); +DATA(insert OID = 1340 ( text PGUID 11 f t f 1 f 25 "1184" 100 0 0 100 timestamp_text - )); +DESCR("convert timestamp to text"); +DATA(insert OID = 1341 ( text PGUID 11 f t f 1 f 25 "1186" 100 0 0 100 interval_text - )); +DESCR("convert interval to text"); DATA(insert OID = 1342 ( text PGUID 11 f t t 1 f 25 "23" 100 0 0 100 int4_text - )); DESCR("convert int4 to text"); DATA(insert OID = 1343 ( text PGUID 11 f t t 1 f 25 "21" 100 0 0 100 int2_text - )); @@ -1617,48 +1597,42 @@ DESCR("get description for object id"); DATA(insert OID = 1349 ( oidvectortypes PGUID 11 f t f 1 f 25 "30" 100 0 0 100 oidvectortypes - )); DESCR("print type names of oidvector field"); -DATA(insert OID = 1350 ( datetime PGUID 14 f t f 1 f 1184 "1184" 100 0 0 100 "select $1" - )); +DATA(insert OID = 1350 ( timestamp PGUID 14 f t f 1 f 1184 "1184" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1351 ( datetime PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1352 ( datetime PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_datetime - )); -DESCR("convert abstime to datetime"); -DATA(insert OID = 1353 ( datetime PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_datetime - )); -DESCR("convert date to datetime"); -DATA(insert OID = 1354 ( datetime PGUID 11 f t f 1 f 1184 "1296" 100 0 0 100 timestamp_datetime - )); -DESCR("convert timestamp to datetime"); -DATA(insert OID = 1355 ( datetime PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_datetime - )); -DESCR("convert date and time to datetime"); -DATA(insert OID = 1356 ( timespan PGUID 14 f t t 1 f 1186 "1186" 100 0 0 100 "select $1" - )); +DATA(insert OID = 1351 ( timestamp PGUID 11 f t f 1 f 1184 "25" 100 0 0 100 text_timestamp - )); +DESCR("convert text to timestamp"); +DATA(insert OID = 1352 ( timestamp PGUID 11 f t f 1 f 1184 "702" 100 0 0 100 abstime_timestamp - )); +DESCR("convert abstime to timestamp"); +DATA(insert OID = 1353 ( timestamp PGUID 11 f t f 1 f 1184 "1082" 100 0 0 100 date_timestamp - )); +DESCR("convert date to timestamp"); +DATA(insert OID = 1355 ( timestamp PGUID 11 f t f 2 f 1184 "1082 1083" 100 0 0 100 datetime_timestamp - )); +DESCR("convert date and time to timestamp"); +DATA(insert OID = 1356 ( interval PGUID 14 f t t 1 f 1186 "1186" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1357 ( timespan PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_timespan - )); -DESCR("convert reltime to timespan"); -DATA(insert OID = 1358 ( timespan PGUID 14 f t f 1 f 1186 "1083" 100 0 0 100 "select time_timespan($1)" - )); -DESCR("convert time to timespan"); +DATA(insert OID = 1357 ( interval PGUID 11 f t f 1 f 1186 "703" 100 0 0 100 reltime_interval - )); +DESCR("convert reltime to interval"); +DATA(insert OID = 1358 ( interval PGUID 14 f t f 1 f 1186 "1083" 100 0 0 100 "select time_interval($1)" - )); +DESCR("convert time to interval"); DATA(insert OID = 1359 ( date PGUID 14 f t t 1 f 1082 "1082" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1360 ( date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 datetime_date - )); -DESCR("convert datetime to date"); +DATA(insert OID = 1360 ( date PGUID 11 f t f 1 f 1082 "1184" 100 0 0 100 timestamp_date - )); +DESCR("convert timestamp to date"); DATA(insert OID = 1361 ( date PGUID 11 f t f 1 f 1082 "702" 100 0 0 100 abstime_date - )); DESCR("convert abstime to date"); DATA(insert OID = 1362 ( time PGUID 14 f t t 1 f 1083 "1083" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1363 ( time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 datetime_time - )); -DESCR("convert datetime to time"); -DATA(insert OID = 1364 ( time PGUID 14 f t f 1 f 1083 "702" 100 0 0 100 "select time(datetime($1))" - )); +DATA(insert OID = 1363 ( time PGUID 11 f t f 1 f 1083 "1184" 100 0 0 100 timestamp_time - )); +DESCR("convert timestamp to time"); +DATA(insert OID = 1364 ( time PGUID 14 f t f 1 f 1083 "702" 100 0 0 100 "select time(timestamp($1))" - )); DESCR("convert abstime to time"); DATA(insert OID = 1365 ( abstime PGUID 14 f t f 1 f 702 "702" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1366 ( abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 datetime_abstime - )); -DESCR("convert datetime to abstime"); +DATA(insert OID = 1366 ( abstime PGUID 11 f t f 1 f 702 "1184" 100 0 0 100 timestamp_abstime - )); +DESCR("convert timestamp to abstime"); DATA(insert OID = 1367 ( reltime PGUID 14 f t t 1 f 703 "703" 100 0 0 100 "select $1" - )); DESCR("convert (noop)"); -DATA(insert OID = 1368 ( reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 timespan_reltime - )); -DESCR("convert timespan to reltime"); -DATA(insert OID = 1369 ( timestamp PGUID 14 f t t 1 f 1296 "1296" 100 0 0 100 "select $1" - )); -DESCR("convert (noop)"); -DATA(insert OID = 1370 ( timestamp PGUID 11 f t f 1 f 1296 "1184" 100 0 0 100 datetime_timestamp - )); -DESCR("convert datetime to timestamp"); +DATA(insert OID = 1368 ( reltime PGUID 11 f t f 1 f 703 "1186" 100 0 0 100 interval_reltime - )); +DESCR("convert interval to reltime"); DATA(insert OID = 1371 ( length PGUID 11 f t t 1 f 23 "25" 100 0 0 100 textlen - )); DESCR("character length"); DATA(insert OID = 1372 ( length PGUID 11 f t t 1 f 23 "1042" 100 0 0 100 bpcharlen - )); @@ -1673,36 +1647,36 @@ DESCR("octet length"); DATA(insert OID = 1376 ( octet_length PGUID 11 f t t 1 f 23 "1043" 100 0 0 100 varcharoctetlen - )); DESCR("octet length"); -DATA(insert OID = 1380 ( date_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 datetime_part - )); -DESCR("extract field from datetime"); -DATA(insert OID = 1381 ( date_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 timespan_part - )); -DESCR("extract field from timespan"); -DATA(insert OID = 1382 ( date_part PGUID 14 f t f 2 f 701 "25 702" 100 0 0 100 "select datetime_part($1, datetime($2))" - )); +DATA(insert OID = 1380 ( date_part PGUID 11 f t f 2 f 701 "25 1184" 100 0 0 100 timestamp_part - )); +DESCR("extract field from timestamp"); +DATA(insert OID = 1381 ( date_part PGUID 11 f t f 2 f 701 "25 1186" 100 0 0 100 interval_part - )); +DESCR("extract field from interval"); +DATA(insert OID = 1382 ( date_part PGUID 14 f t f 2 f 701 "25 702" 100 0 0 100 "select timestamp_part($1, timestamp($2))" - )); DESCR("extract field from abstime"); -DATA(insert OID = 1383 ( date_part PGUID 14 f t f 2 f 701 "25 703" 100 0 0 100 "select timespan_part($1, timespan($2))" - )); +DATA(insert OID = 1383 ( date_part PGUID 14 f t f 2 f 701 "25 703" 100 0 0 100 "select interval_part($1, interval($2))" - )); DESCR("extract field from reltime"); -DATA(insert OID = 1384 ( date_part PGUID 14 f t f 2 f 701 "25 1082" 100 0 0 100 "select datetime_part($1, datetime($2))" - )); +DATA(insert OID = 1384 ( date_part PGUID 14 f t f 2 f 701 "25 1082" 100 0 0 100 "select timestamp_part($1, timestamp($2))" - )); DESCR("extract field from date"); -DATA(insert OID = 1385 ( date_part PGUID 14 f t f 2 f 701 "25 1083" 100 0 0 100 "select timespan_part($1, timespan($2))" - )); +DATA(insert OID = 1385 ( date_part PGUID 14 f t f 2 f 701 "25 1083" 100 0 0 100 "select interval_part($1, interval($2))" - )); DESCR("extract field from time"); -DATA(insert OID = 1386 ( date_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 datetime_trunc - )); -DESCR("truncate datetime to field"); -DATA(insert OID = 1387 ( date_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 timespan_trunc - )); -DESCR("truncate timespan to field"); -DATA(insert OID = 1388 ( age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 datetime_age - )); -DESCR("difference between datetimes but leave years and months unresolved"); -DATA(insert OID = 1389 ( age PGUID 14 f t f 1 f 1186 "1184" 100 0 0 100 "select datetime_age(\'today\', $1)" - )); -DESCR("difference between datetime and today but leave years and months unresolved"); +DATA(insert OID = 1386 ( date_trunc PGUID 11 f t f 2 f 1184 "25 1184" 100 0 0 100 timestamp_trunc - )); +DESCR("truncate timestamp to field"); +DATA(insert OID = 1387 ( date_trunc PGUID 11 f t f 2 f 1186 "25 1186" 100 0 0 100 interval_trunc - )); +DESCR("truncate interval to field"); +DATA(insert OID = 1388 ( age PGUID 11 f t f 2 f 1186 "1184 1184" 100 0 0 100 timestamp_age - )); +DESCR("difference between timestamps but leave years and months unresolved"); +DATA(insert OID = 1389 ( age PGUID 14 f t f 1 f 1186 "1184" 100 0 0 100 "select timestamp_age(\'today\', $1)" - )); +DESCR("difference between timestamp and today but leave years and months unresolved"); -DATA(insert OID = 1390 ( isfinite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 datetime_finite - )); +DATA(insert OID = 1390 ( isfinite PGUID 11 f t f 1 f 16 "1184" 100 0 0 100 timestamp_finite - )); DESCR("boolean test"); -DATA(insert OID = 1391 ( isfinite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 timespan_finite - )); +DATA(insert OID = 1391 ( isfinite PGUID 11 f t f 1 f 16 "1186" 100 0 0 100 interval_finite - )); DESCR("boolean test"); DATA(insert OID = 1392 ( isfinite PGUID 11 f t f 1 f 16 "702" 100 0 0 100 abstime_finite - )); DESCR("boolean test"); -DATA(insert OID = 1393 ( timespan PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_timespan - )); -DESCR("convert text to timespan"); +DATA(insert OID = 1393 ( interval PGUID 11 f t f 1 f 1186 "25" 100 0 0 100 text_interval - )); +DESCR("convert text to interval"); DATA(insert OID = 1394 ( name PGUID 11 f t t 1 f 19 "25" 100 0 0 100 text_name - )); DESCR("convert text to name"); @@ -2352,9 +2326,7 @@ DATA(insert OID = 1769 ( numeric_cmp PGUID 11 f t t 2 f 23 "1700 1700" 100 0 0 DESCR("compare two numbers"); /* formatting */ -DATA(insert OID = 1770 ( to_char PGUID 11 f t f 2 f 25 "1184 25" 100 0 0 100 datetime_to_char - )); -DESCR("convert / formatting datetime to text"); -DATA(insert OID = 1771 ( to_char PGUID 11 f t f 2 f 25 "1296 25" 100 0 0 100 timestamp_to_char - )); +DATA(insert OID = 1770 ( to_char PGUID 11 f t f 2 f 25 "1184 25" 100 0 0 100 timestamp_to_char - )); DESCR("convert / formatting timestamp to text"); DATA(insert OID = 1772 ( to_char PGUID 11 f t f 2 f 25 "1700 25" 100 0 0 100 numeric_to_char - )); DESCR("convert / formatting numeric to text"); @@ -2368,10 +2340,8 @@ DATA(insert OID = 1776 ( to_char PGUID 11 f t f 2 f 25 "701 25" 100 0 0 100 DESCR("convert / formatting float8 to text"); DATA(insert OID = 1777 ( to_number PGUID 11 f t f 2 f 1700 "25 25" 100 0 0 100 numeric_to_number - )); DESCR("convert text to numeric"); -DATA(insert OID = 1778 ( to_datetime PGUID 11 f t f 2 f 1184 "25 25" 100 0 0 100 to_datetime - )); -DESCR("convert text to datetime"); -DATA(insert OID = 1779 ( to_timestamp PGUID 11 f t f 2 f 1296 "25 25" 100 0 0 100 to_timestamp - )); -DESCR("convert text to datetime"); +DATA(insert OID = 1778 ( to_timestamp PGUID 11 f t f 2 f 1184 "25 25" 100 0 0 100 to_timestamp - )); +DESCR("convert text to timestamp"); DATA(insert OID = 1780 ( to_date PGUID 11 f t f 2 f 1082 "25 25" 100 0 0 100 to_date - )); DESCR("convert text to date"); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index b22c80e0f0..fa074460a7 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.80 2000/02/15 03:28:31 thomas Exp $ + * $Id: pg_type.h,v 1.81 2000/02/16 17:26:07 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -370,20 +370,17 @@ DESCR("hh:mm:ss, ANSI SQL time"); /* OIDS 1100 - 1199 */ DATA(insert OID = 1182 ( _date PGUID -1 -1 f b t \054 0 1082 array_in array_out array_in array_out i _null_ )); DATA(insert OID = 1183 ( _time PGUID -1 -1 f b t \054 0 1083 array_in array_out array_in array_out d _null_ )); -DATA(insert OID = 1184 ( datetime PGUID 8 47 f b t \054 0 0 datetime_in datetime_out datetime_in datetime_out d _null_ )); +DATA(insert OID = 1184 ( timestamp PGUID 8 47 f b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out d _null_ )); DESCR("date and time"); -#define DATETIMEOID 1184 -DATA(insert OID = 1185 ( _datetime PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d _null_ )); -DATA(insert OID = 1186 ( timespan PGUID 12 47 f b t \054 0 0 timespan_in timespan_out timespan_in timespan_out d _null_ )); +#define TIMESTAMPOID 1184 +DATA(insert OID = 1185 ( _timestamp PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d _null_ )); +DATA(insert OID = 1186 ( interval PGUID 12 47 f b t \054 0 0 interval_in interval_out interval_in interval_out d _null_ )); DESCR("@ , time interval"); -#define TIMESPANOID 1186 -DATA(insert OID = 1187 ( _timespan PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d _null_ )); +#define INTERVALOID 1186 +DATA(insert OID = 1187 ( _interval PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d _null_ )); /* OIDS 1200 - 1299 */ DATA(insert OID = 1231 ( _numeric PGUID -1 -1 f b t \054 0 1700 array_in array_out array_in array_out i _null_ )); -DATA(insert OID = 1296 ( timestamp PGUID 4 19 t b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out i _null_ )); -DESCR("date time timezone, limited-range ISO-formated date and time"); -#define TIMESTAMPOID 1296 /* OIDS 1700 - 1799 */ DATA(insert OID = 1700 ( numeric PGUID -1 -1 f b t \054 0 0 numeric_in numeric_out numeric_in numeric_out i _null_ )); diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index bedaaa37bd..54107ef3b8 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_coerce.h,v 1.17 2000/01/26 05:58:27 momjian Exp $ + * $Id: parse_coerce.h,v 1.18 2000/02/16 17:26:16 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -48,8 +48,9 @@ typedef enum CATEGORY || ((t) == INT4OID) \ || ((t) == INT8OID) \ || ((t) == FLOAT8OID) \ - || ((t) == DATETIMEOID) \ + || ((t) == NUMERICOID) \ || ((t) == TIMESTAMPOID) \ + || ((t) == INTERVALOID) \ || ((t) == ABSTIMEOID) \ || ((t) == RELTIMEOID) \ || ((t) == CHAROID) \ @@ -70,8 +71,8 @@ typedef enum CATEGORY * Check for types with the same underlying binary representation. * This allows us to cheat and directly exchange values without * going through the trouble of calling a conversion function. - * Remove equivalencing of FLOAT8 and DATETIME. They really are not - * close enough in behavior, with the DATETIME reserved values + * Remove equivalencing of FLOAT8 and TIMESTAMP. They really are not + * close enough in behavior, with the TIMESTAMP reserved values * and special formatting. - thomas 1999-01-24 */ #define IS_BINARY_COMPATIBLE(a,b) \ @@ -87,12 +88,8 @@ typedef enum CATEGORY || ((a) == INT4OID && (b) == REGPROCOID) \ || ((a) == REGPROCOID && (b) == OIDOID) \ || ((a) == REGPROCOID && (b) == INT4OID) \ - || ((a) == ABSTIMEOID && (b) == TIMESTAMPOID) \ || ((a) == ABSTIMEOID && (b) == INT4OID) \ - || ((a) == TIMESTAMPOID && (b) == ABSTIMEOID) \ - || ((a) == TIMESTAMPOID && (b) == INT4OID) \ || ((a) == INT4OID && (b) == ABSTIMEOID) \ - || ((a) == INT4OID && (b) == TIMESTAMPOID) \ || ((a) == RELTIMEOID && (b) == INT4OID) \ || ((a) == INT4OID && (b) == RELTIMEOID) \ || ((a) == INETOID && (b) == CIDROID) \ @@ -104,21 +101,21 @@ typedef enum CATEGORY #define IS_HIGHER_TYPE(t) \ (((t) == TEXTOID) \ || ((t) == FLOAT8OID) \ - || ((t) == TIMESPANOID) \ - || ((t) == DATETIMEOID) \ + || ((t) == INTERVALOID) \ + || ((t) == TIMESTAMPOID) \ || ((t) == POLYGONOID) \ || ((t) == INETOID) ) /* IS_HIGHEST_TYPE() * These types are the most general in each of the type categories. - * Since timespan and datetime overload so many functions, let's - * give datetime the preference. + * Since interval and timestamp overload so many functions, let's + * give timestamp the preference. * Since text is a generic string type let's leave it out too. */ #define IS_HIGHEST_TYPE(t) \ (((t) == FLOAT8OID) \ - || ((t) == DATETIMEOID) \ - || ((t) == TIMESPANOID)) + || ((t) == TIMESTAMPOID) \ + || ((t) == INTERVALOID)) extern bool IsPreferredType(CATEGORY category, Oid type); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 7f9dcc6c46..df8dad8dc3 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.101 2000/02/15 20:49:27 tgl Exp $ + * $Id: builtins.h,v 1.102 2000/02/16 17:26:25 thomas Exp $ * * NOTES * This should normally only be included by fmgr.h. @@ -27,12 +27,14 @@ #include "nodes/relation.h" /* for amcostestimate parameters */ #include "storage/itemptr.h" #include "utils/array.h" -#include "utils/datetime.h" -#include "utils/geo_decls.h" #include "utils/inet.h" #include "utils/int8.h" -#include "utils/nabstime.h" +#include "utils/geo_decls.h" #include "utils/numeric.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/nabstime.h" +#include "utils/date.h" /* * Defined in adt/ @@ -204,46 +206,6 @@ extern int32 pqtest(struct varlena * vlena); /* arrayfuncs.c */ -/* date.c */ -extern RelativeTime reltimein(char *timestring); -extern char *reltimeout(RelativeTime timevalue); -extern TimeInterval tintervalin(char *intervalstr); -extern char *tintervalout(TimeInterval interval); -extern RelativeTime timespan_reltime(TimeSpan *timespan); -extern TimeSpan *reltime_timespan(RelativeTime reltime); -extern TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2); -extern AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2); -extern AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2); - -/* extern RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2); static*/ -extern int ininterval(AbsoluteTime t, TimeInterval interval); -extern RelativeTime intervalrel(TimeInterval interval); -extern AbsoluteTime timenow(void); -extern bool reltimeeq(RelativeTime t1, RelativeTime t2); -extern bool reltimene(RelativeTime t1, RelativeTime t2); -extern bool reltimelt(RelativeTime t1, RelativeTime t2); -extern bool reltimegt(RelativeTime t1, RelativeTime t2); -extern bool reltimele(RelativeTime t1, RelativeTime t2); -extern bool reltimege(RelativeTime t1, RelativeTime t2); -extern bool intervalsame(TimeInterval i1, TimeInterval i2); -extern bool intervaleq(TimeInterval i1, TimeInterval i2); -extern bool intervalne(TimeInterval i1, TimeInterval i2); -extern bool intervallt(TimeInterval i1, TimeInterval i2); -extern bool intervalgt(TimeInterval i1, TimeInterval i2); -extern bool intervalle(TimeInterval i1, TimeInterval i2); -extern bool intervalge(TimeInterval i1, TimeInterval i2); -extern bool intervalleneq(TimeInterval i, RelativeTime t); -extern bool intervallenne(TimeInterval i, RelativeTime t); -extern bool intervallenlt(TimeInterval i, RelativeTime t); -extern bool intervallengt(TimeInterval i, RelativeTime t); -extern bool intervallenle(TimeInterval i, RelativeTime t); -extern bool intervallenge(TimeInterval i, RelativeTime t); -extern bool intervalct(TimeInterval i1, TimeInterval i2); -extern bool intervalov(TimeInterval i1, TimeInterval i2); -extern AbsoluteTime intervalstart(TimeInterval i); -extern AbsoluteTime intervalend(TimeInterval i); -extern text *timeofday(void); - /* filename.c */ extern char *filename_in(char *file); extern char *filename_out(char *s); @@ -326,9 +288,6 @@ extern bool float84le(float64 arg1, float32 arg2); extern bool float84gt(float64 arg1, float32 arg2); extern bool float84ge(float64 arg1, float32 arg2); -/* geo_ops.c, geo_selfuncs.c */ -extern double *box_area(BOX *box); - /* misc.c */ extern bool nullvalue(Datum value, bool *isNull); extern bool nonnullvalue(Datum value, bool *isNull); @@ -432,19 +391,6 @@ extern ItemPointer text_tid(const text *); extern ItemPointer currtid_byreloid(Oid relOid, ItemPointer); extern ItemPointer currtid_byrelname(const text* relName, ItemPointer); -/* timestamp.c */ -extern time_t timestamp_in(const char *timestamp_str); -extern char *timestamp_out(time_t timestamp); -extern time_t now(void); -bool timestampeq(time_t t1, time_t t2); -bool timestampne(time_t t1, time_t t2); -bool timestamplt(time_t t1, time_t t2); -bool timestampgt(time_t t1, time_t t2); -bool timestample(time_t t1, time_t t2); -bool timestampge(time_t t1, time_t t2); -DateTime *timestamp_datetime(time_t timestamp); -time_t datetime_timestamp(DateTime *datetime); - /* varchar.c */ extern char *bpcharin(char *s, int dummy, int32 atttypmod); extern char *bpcharout(char *s); @@ -508,38 +454,6 @@ extern int32 byteaGetBit(struct varlena * v, int32 n); extern struct varlena *byteaSetByte(struct varlena * v, int32 n, int32 newByte); extern struct varlena *byteaSetBit(struct varlena * v, int32 n, int32 newBit); -/* datetime.c */ -extern DateADT date_in(char *datestr); -extern char *date_out(DateADT dateVal); -extern bool date_eq(DateADT dateVal1, DateADT dateVal2); -extern bool date_ne(DateADT dateVal1, DateADT dateVal2); -extern bool date_lt(DateADT dateVal1, DateADT dateVal2); -extern bool date_le(DateADT dateVal1, DateADT dateVal2); -extern bool date_gt(DateADT dateVal1, DateADT dateVal2); -extern bool date_ge(DateADT dateVal1, DateADT dateVal2); -extern int date_cmp(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_larger(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_smaller(DateADT dateVal1, DateADT dateVal2); -extern int32 date_mi(DateADT dateVal1, DateADT dateVal2); -extern DateADT date_pli(DateADT dateVal, int32 days); -extern DateADT date_mii(DateADT dateVal, int32 days); -extern DateTime *date_datetime(DateADT date); -extern DateADT datetime_date(DateTime *datetime); -extern DateTime *datetime_datetime(DateADT date, TimeADT *time); -extern DateADT abstime_date(AbsoluteTime abstime); - -extern TimeADT *time_in(char *timestr); -extern char *time_out(TimeADT *time); -extern bool time_eq(TimeADT *time1, TimeADT *time2); -extern bool time_ne(TimeADT *time1, TimeADT *time2); -extern bool time_lt(TimeADT *time1, TimeADT *time2); -extern bool time_le(TimeADT *time1, TimeADT *time2); -extern bool time_gt(TimeADT *time1, TimeADT *time2); -extern bool time_ge(TimeADT *time1, TimeADT *time2); -extern int time_cmp(TimeADT *time1, TimeADT *time2); -extern TimeADT *datetime_time(DateTime *datetime); -extern int32 int4reltime(int32 timevalue); - /* like.c */ extern bool namelike(NameData *n, struct varlena * p); extern bool namenlike(NameData *s, struct varlena * p); diff --git a/src/include/utils/date.h b/src/include/utils/date.h new file mode 100644 index 0000000000..003ee2e026 --- /dev/null +++ b/src/include/utils/date.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * date.h + * Definitions for the SQL92 "date" and "time" types. + * + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: date.h,v 1.1 2000/02/16 17:26:26 thomas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef DATE_H +#define DATE_H + +typedef int32 DateADT; + +typedef float8 TimeADT; + +/* date.c */ +extern DateADT date_in(char *datestr); +extern char *date_out(DateADT dateVal); +extern bool date_eq(DateADT dateVal1, DateADT dateVal2); +extern bool date_ne(DateADT dateVal1, DateADT dateVal2); +extern bool date_lt(DateADT dateVal1, DateADT dateVal2); +extern bool date_le(DateADT dateVal1, DateADT dateVal2); +extern bool date_gt(DateADT dateVal1, DateADT dateVal2); +extern bool date_ge(DateADT dateVal1, DateADT dateVal2); +extern int date_cmp(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_larger(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_smaller(DateADT dateVal1, DateADT dateVal2); +extern int32 date_mi(DateADT dateVal1, DateADT dateVal2); +extern DateADT date_pli(DateADT dateVal, int32 days); +extern DateADT date_mii(DateADT dateVal, int32 days); +extern Timestamp *date_timestamp(DateADT date); +extern DateADT timestamp_date(Timestamp *timestamp); +extern Timestamp *datetime_timestamp(DateADT date, TimeADT *time); +extern DateADT abstime_date(AbsoluteTime abstime); + +extern TimeADT *time_in(char *timestr); +extern char *time_out(TimeADT *time); +extern bool time_eq(TimeADT *time1, TimeADT *time2); +extern bool time_ne(TimeADT *time1, TimeADT *time2); +extern bool time_lt(TimeADT *time1, TimeADT *time2); +extern bool time_le(TimeADT *time1, TimeADT *time2); +extern bool time_gt(TimeADT *time1, TimeADT *time2); +extern bool time_ge(TimeADT *time1, TimeADT *time2); +extern int time_cmp(TimeADT *time1, TimeADT *time2); +extern TimeADT *timestamp_time(Timestamp *timestamp); + +#endif /* DATE_H */ diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 2a97f5e0dd..3df9ddf19f 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -1,21 +1,438 @@ /*------------------------------------------------------------------------- * * datetime.h - * Definitions for the datetime + * Definitions for the date/time and other date/time support code. + * The support code is shared with other date data types, + * including abstime, reltime, date, and time. * * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: datetime.h,v 1.9 2000/01/26 05:58:37 momjian Exp $ + * $Id: datetime.h,v 1.10 2000/02/16 17:26:26 thomas Exp $ * *------------------------------------------------------------------------- */ #ifndef DATETIME_H #define DATETIME_H -typedef int32 DateADT; +#include +#include +#include +#include "utils/timestamp.h" + +#if 0 + + +/* + * Timestamp represents absolute time. + * TimeSpan represents delta time. Keep track of months (and years) + * separately since the elapsed time spanned is unknown until instantiated + * relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + */ + +typedef double Timestamp; + +typedef struct +{ + double time; /* all time units other than months and + * years */ + int4 month; /* months and years, after time for + * alignment */ +} TimeSpan; + + +#endif + + +/* ---------------------------------------------------------------- + * time types + support macros + * + * String definitions for standard time quantities. + * + * These strings are the defaults used to form output time strings. + * Other alternate forms are hardcoded into token tables in datetime.c. + * ---------------------------------------------------------------- + */ + +#define DAGO "ago" +#define DCURRENT "current" +#define EPOCH "epoch" +#define INVALID "invalid" +#define EARLY "-infinity" +#define LATE "infinity" +#define NOW "now" +#define TODAY "today" +#define TOMORROW "tomorrow" +#define YESTERDAY "yesterday" +#define ZULU "zulu" + +#define DMICROSEC "usecond" +#define DMILLISEC "msecond" +#define DSECOND "second" +#define DMINUTE "minute" +#define DHOUR "hour" +#define DDAY "day" +#define DWEEK "week" +#define DMONTH "month" +#define DQUARTER "quarter" +#define DYEAR "year" +#define DDECADE "decade" +#define DCENTURY "century" +#define DMILLENIUM "millenium" +#define DA_D "ad" +#define DB_C "bc" +#define DTIMEZONE "timezone" + +/* + * Fundamental time field definitions for parsing. + * + * Meridian: am, pm, or 24-hour style. + * Millenium: ad, bc + */ + +#define AM 0 +#define PM 1 +#define HR24 2 + +#define AD 0 +#define BC 1 + +/* + * Fields for time decoding. + * Can't have more of these than there are bits in an unsigned int + * since these are turned into bit masks during parsing and decoding. + */ + +#define RESERV 0 +#define MONTH 1 +#define YEAR 2 +#define DAY 3 +#define TIMES 4 /* not used - thomas 1997-07-14 */ +#define TZ 5 +#define DTZ 6 +#define DTZMOD 7 +#define IGNORE 8 +#define AMPM 9 +#define HOUR 10 +#define MINUTE 11 +#define SECOND 12 +#define DOY 13 +#define DOW 14 +#define UNITS 15 +#define ADBC 16 +/* these are only for relative dates */ +#define AGO 17 +#define ABS_BEFORE 18 +#define ABS_AFTER 19 + +/* + * Token field definitions for time parsing and decoding. + * These need to fit into the datetkn table type. + * At the moment, that means keep them within [-127,127]. + * These are also used for bit masks in DecodeDateDelta() + * so actually restrict them to within [0,31] for now. + * - thomas 97/06/19 + * Not all of these fields are used for masks in DecodeDateDelta + * so allow some larger than 31. - thomas 1997-11-17 + */ + +#define DTK_NUMBER 0 +#define DTK_STRING 1 + +#define DTK_DATE 2 +#define DTK_TIME 3 +#define DTK_TZ 4 +#define DTK_AGO 5 + +#define DTK_SPECIAL 6 +#define DTK_INVALID 7 +#define DTK_CURRENT 8 +#define DTK_EARLY 9 +#define DTK_LATE 10 +#define DTK_EPOCH 11 +#define DTK_NOW 12 +#define DTK_YESTERDAY 13 +#define DTK_TODAY 14 +#define DTK_TOMORROW 15 +#define DTK_ZULU 16 + +#define DTK_DELTA 17 +#define DTK_SECOND 18 +#define DTK_MINUTE 19 +#define DTK_HOUR 20 +#define DTK_DAY 21 +#define DTK_WEEK 22 +#define DTK_MONTH 23 +#define DTK_QUARTER 24 +#define DTK_YEAR 25 +#define DTK_DECADE 26 +#define DTK_CENTURY 27 +#define DTK_MILLENIUM 28 +#define DTK_MILLISEC 29 +#define DTK_MICROSEC 30 + +#define DTK_DOW 32 +#define DTK_DOY 33 +#define DTK_TZ_HOUR 34 +#define DTK_TZ_MINUTE 35 + +/* + * Bit mask definitions for time parsing. + */ + +#define DTK_M(t) (0x01 << (t)) + +#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) +#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) + +#define MAXDATELEN 47 /* maximum possible length of an input + * date string */ +#define MAXDATEFIELDS 25 /* maximum possible number of fields in a + * date string */ +#define TOKMAXLEN 10 /* only this many chars are stored in + * datetktbl */ + +/* keep this struct small; it gets used a lot */ +typedef struct +{ +#if defined(_AIX) + char *token; +#else + char token[TOKMAXLEN]; +#endif /* _AIX */ + char type; + char value; /* this may be unsigned, alas */ +} datetkn; + + +#if 0 + + +#ifdef NAN +#define TIMESTAMP_INVALID (NAN) +#else +#define TIMESTAMP_INVALID (DBL_MIN+DBL_MIN) +#endif +#ifdef HUGE_VAL +#define TIMESTAMP_NOBEGIN (-HUGE_VAL) +#define TIMESTAMP_NOEND (HUGE_VAL) +#else +#define TIMESTAMP_NOBEGIN (-DBL_MAX) +#define TIMESTAMP_NOEND (DBL_MAX) +#endif +#define TIMESTAMP_CURRENT (DBL_MIN) +#define TIMESTAMP_EPOCH (-DBL_MIN) + +#define TIMESTAMP_INVALID(j) {j = TIMESTAMP_INVALID;} +#ifdef NAN +#define TIMESTAMP_IS_INVALID(j) (isnan(j)) +#else +#define TIMESTAMP_IS_INVALID(j) (j == TIMESTAMP_INVALID) +#endif + +#define TIMESTAMP_NOBEGIN(j) {j = DT_NOBEGIN;} +#define TIMESTAMP_IS_NOBEGIN(j) (j == TIMESTAMP_NOBEGIN) + +#define TIMESTAMP_NOEND(j) {j = TIMESTAMP_NOEND;} +#define TIMESTAMP_IS_NOEND(j) (j == TIMESTAMP_NOEND) + +#define TIMESTAMP_CURRENT(j) {j = TIMESTAMP_CURRENT;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_current(double j); + +#define TIMESTAMP_IS_CURRENT(j) timestamp_is_current(j) +#else +#define TIMESTAMP_IS_CURRENT(j) (j == TIMESTAMP_CURRENT) +#endif + +#define TIMESTAMP_EPOCH(j) {j = TIMESTAMP_EPOCH;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_epoch(double j); + +#define TIMESTAMP_IS_EPOCH(j) timestamp_is_epoch(j) +#else +#define TIMESTAMP_IS_EPOCH(j) (j == TIMESTAMP_EPOCH) +#endif + +#define TIMESTAMP_IS_RELATIVE(j) (TIMESTAMP_IS_CURRENT(j) || TIMESTAMP_IS_EPOCH(j)) +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_INVALID(j) \ + || TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) +#define TIMESTAMP_IS_RESERVED(j) (TIMESTAMP_IS_RELATIVE(j) || TIMESTAMP_NOT_FINITE(j)) + +#define TIMESPAN_INVALID(j) {(j).time = DT_INVALID;} +#ifdef NAN +#define TIMESPAN_IS_INVALID(j) (isnan((j).time)) +#else +#define TIMESPAN_IS_INVALID(j) ((j).time == DATETIME_INVALID) +#endif +#define TIMESPAN_NOT_FINITE(j) TIMESPAN_IS_INVALID(j) + +#define TIME_PREC_INV 1000000.0 +#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) + + +#endif + +/* TMODULO() + * Macro to replace modf(), which is broken on some platforms. + */ +#define TMODULO(t,q,u) \ +do { \ + q = ((t < 0)? ceil(t / u): floor(t / u)); \ + if (q != 0) \ + t -= rint(q * u); \ +} while(0) + + +/* + * Date/time validation + * Include check for leap year. + */ + +extern int day_tab[2][13]; + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* Julian date support for date2j() and j2date() + * Set the minimum year to one greater than the year of the first valid day + * to avoid having to check year and day both. - tgl 97/05/08 + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (23) + +#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ + || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ + || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#if 0 + + +/* + * datetime.c prototypes + */ + +extern DateTime *datetime_in(char *str); +extern char *datetime_out(DateTime *dt); +extern bool datetime_eq(DateTime *dt1, DateTime *dt2); +extern bool datetime_ne(DateTime *dt1, DateTime *dt2); +extern bool datetime_lt(DateTime *dt1, DateTime *dt2); +extern bool datetime_le(DateTime *dt1, DateTime *dt2); +extern bool datetime_ge(DateTime *dt1, DateTime *dt2); +extern bool datetime_gt(DateTime *dt1, DateTime *dt2); +extern bool datetime_finite(DateTime *datetime); +extern int datetime_cmp(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_smaller(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_larger(DateTime *dt1, DateTime *dt2); + +extern TimeSpan *timespan_in(char *str); +extern char *timespan_out(TimeSpan *span); +extern bool timespan_eq(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_ne(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_le(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2); +extern bool timespan_finite(TimeSpan *span); +extern int timespan_cmp(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_smaller(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_larger(TimeSpan *span1, TimeSpan *span2); + +extern text *datetime_text(DateTime *datetime); +extern DateTime *text_datetime(text *str); +extern text *timespan_text(TimeSpan *timespan); +extern TimeSpan *text_timespan(text *str); +extern DateTime *datetime_trunc(text *units, DateTime *datetime); +extern TimeSpan *timespan_trunc(text *units, TimeSpan *timespan); +extern float64 datetime_part(text *units, DateTime *datetime); +extern float64 timespan_part(text *units, TimeSpan *timespan); +extern text *datetime_zone(text *zone, DateTime *datetime); + +extern TimeSpan *timespan_um(TimeSpan *span); +extern TimeSpan *timespan_pl(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_mi(TimeSpan *span1, TimeSpan *span2); +extern TimeSpan *timespan_div(TimeSpan *span1, float8 *arg2); + +extern TimeSpan *datetime_mi(DateTime *dt1, DateTime *dt2); +extern DateTime *datetime_pl_span(DateTime *dt, TimeSpan *span); +extern DateTime *datetime_mi_span(DateTime *dt, TimeSpan *span); +extern TimeSpan *datetime_age(DateTime *dt1, DateTime *dt2); + + +#endif + + +extern void GetCurrentTime(struct tm * tm); +extern void j2date(int jd, int *year, int *month, int *day); +extern int date2j(int year, int month, int day); + +extern int ParseDateTime(char *timestr, char *lowstr, + char **field, int *ftype, + int maxfields, int *numfields); +extern int DecodeDateTime(char **field, int *ftype, + int nf, int *dtype, + struct tm * tm, double *fsec, int *tzp); + +extern int DecodeTimeOnly(char **field, int *ftype, int nf, + int *dtype, struct tm * tm, double *fsec); + +extern int DecodeDateDelta(char **field, int *ftype, + int nf, int *dtype, + struct tm * tm, double *fsec); + +extern int EncodeDateOnly(struct tm * tm, int style, char *str); +extern int EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str); +extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str); +extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str); + +extern int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); +extern int DecodeNumber(int flen, char *field, + int fmask, int *tmask, + struct tm * tm, double *fsec, int *is2digits); +extern int DecodeNumberField(int len, char *str, + int fmask, int *tmask, + struct tm * tm, double *fsec, int *is2digits); +extern int DecodeSpecial(int field, char *lowtoken, int *val); +extern int DecodeTime(char *str, int fmask, int *tmask, + struct tm * tm, double *fsec); +extern int DecodeTimezone(char *str, int *tzp); +extern int DecodeUnits(int field, char *lowtoken, int *val); +extern datetkn *datebsearch(char *key, datetkn *base, unsigned int nel); + +extern int j2day(int jd); + + +#if 0 + + +static int EncodeSpecialTimestamp(Timestamp dt, char *str); +static Timestamp dt2local(Timestamp dt, int timezone); +static void dt2time(Timestamp dt, int *hour, int *min, double *sec); +static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec); +static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span); + + +#endif -typedef float8 TimeADT; #endif /* DATETIME_H */ diff --git a/src/include/utils/dt.h b/src/include/utils/dt.h deleted file mode 100644 index 739c3c22ba..0000000000 --- a/src/include/utils/dt.h +++ /dev/null @@ -1,378 +0,0 @@ -/*------------------------------------------------------------------------- - * - * dt.h - * Definitions for the date/time and other date/time support code. - * The support code is shared with other date data types, - * including abstime, reltime, date, and time. - * - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * $Id: dt.h,v 1.42 2000/01/26 05:58:37 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#ifndef DT_H -#define DT_H - -#include -#include -#include - -/* - * DateTime represents absolute time. - * TimeSpan represents delta time. Keep track of months (and years) - * separately since the elapsed time spanned is unknown until instantiated - * relative to an absolute time. - * - * Note that Postgres uses "time interval" to mean a bounded interval, - * consisting of a beginning and ending time, not a time span - thomas 97/03/20 - */ - -typedef double DateTime; - -typedef struct -{ - double time; /* all time units other than months and - * years */ - int4 month; /* months and years, after time for - * alignment */ -} TimeSpan; - - -/* ---------------------------------------------------------------- - * time types + support macros - * - * String definitions for standard time quantities. - * - * These strings are the defaults used to form output time strings. - * Other alternate forms are hardcoded into token tables in dt.c. - * ---------------------------------------------------------------- - */ - -#define DAGO "ago" -#define DCURRENT "current" -#define EPOCH "epoch" -#define INVALID "invalid" -#define EARLY "-infinity" -#define LATE "infinity" -#define NOW "now" -#define TODAY "today" -#define TOMORROW "tomorrow" -#define YESTERDAY "yesterday" -#define ZULU "zulu" - -#define DMICROSEC "usecond" -#define DMILLISEC "msecond" -#define DSECOND "second" -#define DMINUTE "minute" -#define DHOUR "hour" -#define DDAY "day" -#define DWEEK "week" -#define DMONTH "month" -#define DQUARTER "quarter" -#define DYEAR "year" -#define DDECADE "decade" -#define DCENTURY "century" -#define DMILLENIUM "millenium" -#define DA_D "ad" -#define DB_C "bc" -#define DTIMEZONE "timezone" - -/* - * Fundamental time field definitions for parsing. - * - * Meridian: am, pm, or 24-hour style. - * Millenium: ad, bc - */ - -#define AM 0 -#define PM 1 -#define HR24 2 - -#define AD 0 -#define BC 1 - -/* - * Fields for time decoding. - * Can't have more of these than there are bits in an unsigned int - * since these are turned into bit masks during parsing and decoding. - */ - -#define RESERV 0 -#define MONTH 1 -#define YEAR 2 -#define DAY 3 -#define TIMES 4 /* not used - thomas 1997-07-14 */ -#define TZ 5 -#define DTZ 6 -#define DTZMOD 7 -#define IGNORE 8 -#define AMPM 9 -#define HOUR 10 -#define MINUTE 11 -#define SECOND 12 -#define DOY 13 -#define DOW 14 -#define UNITS 15 -#define ADBC 16 -/* these are only for relative dates */ -#define AGO 17 -#define ABS_BEFORE 18 -#define ABS_AFTER 19 - -/* - * Token field definitions for time parsing and decoding. - * These need to fit into the datetkn table type. - * At the moment, that means keep them within [-127,127]. - * These are also used for bit masks in DecodeDateDelta() - * so actually restrict them to within [0,31] for now. - * - thomas 97/06/19 - * Not all of these fields are used for masks in DecodeDateDelta - * so allow some larger than 31. - thomas 1997-11-17 - */ - -#define DTK_NUMBER 0 -#define DTK_STRING 1 - -#define DTK_DATE 2 -#define DTK_TIME 3 -#define DTK_TZ 4 -#define DTK_AGO 5 - -#define DTK_SPECIAL 6 -#define DTK_INVALID 7 -#define DTK_CURRENT 8 -#define DTK_EARLY 9 -#define DTK_LATE 10 -#define DTK_EPOCH 11 -#define DTK_NOW 12 -#define DTK_YESTERDAY 13 -#define DTK_TODAY 14 -#define DTK_TOMORROW 15 -#define DTK_ZULU 16 - -#define DTK_DELTA 17 -#define DTK_SECOND 18 -#define DTK_MINUTE 19 -#define DTK_HOUR 20 -#define DTK_DAY 21 -#define DTK_WEEK 22 -#define DTK_MONTH 23 -#define DTK_QUARTER 24 -#define DTK_YEAR 25 -#define DTK_DECADE 26 -#define DTK_CENTURY 27 -#define DTK_MILLENIUM 28 -#define DTK_MILLISEC 29 -#define DTK_MICROSEC 30 - -#define DTK_DOW 32 -#define DTK_DOY 33 -#define DTK_TZ_HOUR 34 -#define DTK_TZ_MINUTE 35 - -/* - * Bit mask definitions for time parsing. - */ - -#define DTK_M(t) (0x01 << (t)) - -#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) -#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) - -#define MAXDATELEN 47 /* maximum possible length of an input - * date string */ -#define MAXDATEFIELDS 25 /* maximum possible number of fields in a - * date string */ -#define TOKMAXLEN 10 /* only this many chars are stored in - * datetktbl */ - -/* keep this struct small; it gets used a lot */ -typedef struct -{ -#if defined(_AIX) - char *token; -#else - char token[TOKMAXLEN]; -#endif /* _AIX */ - char type; - char value; /* this may be unsigned, alas */ -} datetkn; - -#ifdef NAN -#define DT_INVALID (NAN) -#else -#define DT_INVALID (DBL_MIN+DBL_MIN) -#endif -#ifdef HUGE_VAL -#define DT_NOBEGIN (-HUGE_VAL) -#define DT_NOEND (HUGE_VAL) -#else -#define DT_NOBEGIN (-DBL_MAX) -#define DT_NOEND (DBL_MAX) -#endif -#define DT_CURRENT (DBL_MIN) -#define DT_EPOCH (-DBL_MIN) - -#define DATETIME_INVALID(j) {j = DT_INVALID;} -#ifdef NAN -#define DATETIME_IS_INVALID(j) (isnan(j)) -#else -#define DATETIME_IS_INVALID(j) (j == DT_INVALID) -#endif - -#define DATETIME_NOBEGIN(j) {j = DT_NOBEGIN;} -#define DATETIME_IS_NOBEGIN(j) (j == DT_NOBEGIN) - -#define DATETIME_NOEND(j) {j = DT_NOEND;} -#define DATETIME_IS_NOEND(j) (j == DT_NOEND) - -#define DATETIME_CURRENT(j) {j = DT_CURRENT;} -#if defined(linux) && defined(__powerpc__) -extern int datetime_is_current(double j); - -#define DATETIME_IS_CURRENT(j) datetime_is_current(j) -#else -#define DATETIME_IS_CURRENT(j) (j == DT_CURRENT) -#endif - -#define DATETIME_EPOCH(j) {j = DT_EPOCH;} -#if defined(linux) && defined(__powerpc__) -extern int datetime_is_epoch(double j); - -#define DATETIME_IS_EPOCH(j) datetime_is_epoch(j) -#else -#define DATETIME_IS_EPOCH(j) (j == DT_EPOCH) -#endif - -#define DATETIME_IS_RELATIVE(j) (DATETIME_IS_CURRENT(j) || DATETIME_IS_EPOCH(j)) -#define DATETIME_NOT_FINITE(j) (DATETIME_IS_INVALID(j) \ - || DATETIME_IS_NOBEGIN(j) || DATETIME_IS_NOEND(j)) -#define DATETIME_IS_RESERVED(j) (DATETIME_IS_RELATIVE(j) || DATETIME_NOT_FINITE(j)) - -#define TIMESPAN_INVALID(j) {(j).time = DT_INVALID;} -#ifdef NAN -#define TIMESPAN_IS_INVALID(j) (isnan((j).time)) -#else -#define TIMESPAN_IS_INVALID(j) ((j).time == DT_INVALID) -#endif -#define TIMESPAN_NOT_FINITE(j) TIMESPAN_IS_INVALID(j) - -#define TIME_PREC_INV 1000000.0 -#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) - - - -/* - * Date/time validation - * Include check for leap year. - */ - -extern int day_tab[2][13]; - -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - -/* Julian date support for date2j() and j2date() - * Set the minimum year to one greater than the year of the first valid day - * to avoid having to check year and day both. - tgl 97/05/08 - */ - -#define JULIAN_MINYEAR (-4713) -#define JULIAN_MINMONTH (11) -#define JULIAN_MINDAY (23) - -#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ - || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ - || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) - -#define UTIME_MINYEAR (1901) -#define UTIME_MINMONTH (12) -#define UTIME_MINDAY (14) -#define UTIME_MAXYEAR (2038) -#define UTIME_MAXMONTH (01) -#define UTIME_MAXDAY (18) - -#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ - || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ - || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ - && ((y < UTIME_MAXYEAR) \ - || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ - || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) - -/* - * dt.c prototypes - */ - -extern DateTime *datetime_in(char *str); -extern char *datetime_out(DateTime *dt); -extern bool datetime_eq(DateTime *dt1, DateTime *dt2); -extern bool datetime_ne(DateTime *dt1, DateTime *dt2); -extern bool datetime_lt(DateTime *dt1, DateTime *dt2); -extern bool datetime_le(DateTime *dt1, DateTime *dt2); -extern bool datetime_ge(DateTime *dt1, DateTime *dt2); -extern bool datetime_gt(DateTime *dt1, DateTime *dt2); -extern bool datetime_finite(DateTime *datetime); -extern int datetime_cmp(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_smaller(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_larger(DateTime *dt1, DateTime *dt2); - -extern TimeSpan *timespan_in(char *str); -extern char *timespan_out(TimeSpan *span); -extern bool timespan_eq(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_ne(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_lt(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_le(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_ge(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_gt(TimeSpan *span1, TimeSpan *span2); -extern bool timespan_finite(TimeSpan *span); -extern int timespan_cmp(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_smaller(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_larger(TimeSpan *span1, TimeSpan *span2); - -extern text *datetime_text(DateTime *datetime); -extern DateTime *text_datetime(text *str); -extern text *timespan_text(TimeSpan *timespan); -extern TimeSpan *text_timespan(text *str); -extern DateTime *datetime_trunc(text *units, DateTime *datetime); -extern TimeSpan *timespan_trunc(text *units, TimeSpan *timespan); -extern float64 datetime_part(text *units, DateTime *datetime); -extern float64 timespan_part(text *units, TimeSpan *timespan); -extern text *datetime_zone(text *zone, DateTime *datetime); - -extern TimeSpan *timespan_um(TimeSpan *span); -extern TimeSpan *timespan_pl(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_mi(TimeSpan *span1, TimeSpan *span2); -extern TimeSpan *timespan_div(TimeSpan *span1, float8 *arg2); - -extern TimeSpan *datetime_mi(DateTime *dt1, DateTime *dt2); -extern DateTime *datetime_pl_span(DateTime *dt, TimeSpan *span); -extern DateTime *datetime_mi_span(DateTime *dt, TimeSpan *span); -extern TimeSpan *datetime_age(DateTime *dt1, DateTime *dt2); - -extern void GetCurrentTime(struct tm * tm); -extern DateTime SetDateTime(DateTime datetime); -extern int tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime *dt); -extern int datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn); - -extern void j2date(int jd, int *year, int *month, int *day); -extern int date2j(int year, int month, int day); - -extern int ParseDateTime(char *timestr, char *lowstr, - char **field, int *ftype, int maxfields, int *numfields); -extern int DecodeDateTime(char **field, int *ftype, - int nf, int *dtype, struct tm * tm, double *fsec, int *tzp); - -extern int DecodeTimeOnly(char **field, int *ftype, int nf, - int *dtype, struct tm * tm, double *fsec); - -extern int DecodeDateDelta(char **field, int *ftype, - int nf, int *dtype, struct tm * tm, double *fsec); - -extern int EncodeDateOnly(struct tm * tm, int style, char *str); -extern int EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str); -extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str); -extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str); - -#endif /* DT_H */ diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index 51c649fd9d..39259afff2 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -2,7 +2,7 @@ /* ----------------------------------------------------------------------- * formatting.h * - * $Id: formatting.h,v 1.2 2000/02/08 15:56:57 momjian Exp $ + * $Id: formatting.h,v 1.3 2000/02/16 17:26:26 thomas Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc @@ -18,16 +18,14 @@ #ifndef _FORMATTING_H_ #define _FORMATTING_H_ -extern text *datetime_to_char(DateTime *dt, text *fmt); -extern text *timestamp_to_char(time_t dt, text *fmt); -extern DateTime *to_datetime(text *date_str, text *fmt); -extern time_t to_timestamp(text *date_str, text *fmt); -extern DateADT to_date(text *date_str, text *fmt); -extern Numeric numeric_to_number(text *value, text *fmt); -extern text *numeric_to_char(Numeric value, text *fmt); -extern text *int4_to_char(int32 value, text *fmt); -extern text *int8_to_char(int64 *value, text *fmt); -extern text *float4_to_char(float32 value, text *fmt); -extern text *float8_to_char(float64 value, text *fmt); +extern text *timestamp_to_char(Timestamp *dt, text *fmt); +extern Timestamp *to_timestamp(text *date_str, text *fmt); +extern DateADT to_date(text *date_str, text *fmt); +extern Numeric numeric_to_number(text *value, text *fmt); +extern text *numeric_to_char(Numeric value, text *fmt); +extern text *int4_to_char(int32 value, text *fmt); +extern text *int8_to_char(int64 *value, text *fmt); +extern text *float4_to_char(float32 value, text *fmt); +extern text *float8_to_char(float64 value, text *fmt); #endif diff --git a/src/include/utils/nabstime.h b/src/include/utils/nabstime.h index 4da1c28343..09eea75ec6 100644 --- a/src/include/utils/nabstime.h +++ b/src/include/utils/nabstime.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nabstime.h,v 1.22 2000/01/26 05:58:38 momjian Exp $ + * $Id: nabstime.h,v 1.23 2000/02/16 17:26:26 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,8 @@ #define NABSTIME_H #include -#include "utils/dt.h" +#include "utils/timestamp.h" +#include "utils/datetime.h" /* ---------------------------------------------------------------- @@ -119,11 +120,51 @@ extern bool abstimele(AbsoluteTime t1, AbsoluteTime t2); extern bool abstimege(AbsoluteTime t1, AbsoluteTime t2); extern bool abstime_finite(AbsoluteTime time); -extern AbsoluteTime datetime_abstime(DateTime *datetime); -extern DateTime *abstime_datetime(AbsoluteTime abstime); +extern AbsoluteTime timestamp_abstime(Timestamp *timestamp); +extern Timestamp *abstime_timestamp(AbsoluteTime abstime); extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2); extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn); +extern RelativeTime reltimein(char *timestring); +extern char *reltimeout(RelativeTime timevalue); +extern TimeInterval tintervalin(char *intervalstr); +extern char *tintervalout(TimeInterval interval); +extern RelativeTime interval_reltime(Interval *interval); +extern Interval *reltime_interval(RelativeTime reltime); +extern TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2); +extern AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2); +extern AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2); + +/* extern RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2); static*/ +extern int intinterval(AbsoluteTime t, TimeInterval interval); +extern RelativeTime tintervalrel(TimeInterval interval); +extern AbsoluteTime timenow(void); +extern bool reltimeeq(RelativeTime t1, RelativeTime t2); +extern bool reltimene(RelativeTime t1, RelativeTime t2); +extern bool reltimelt(RelativeTime t1, RelativeTime t2); +extern bool reltimegt(RelativeTime t1, RelativeTime t2); +extern bool reltimele(RelativeTime t1, RelativeTime t2); +extern bool reltimege(RelativeTime t1, RelativeTime t2); +extern bool tintervalsame(TimeInterval i1, TimeInterval i2); +extern bool tintervaleq(TimeInterval i1, TimeInterval i2); +extern bool tintervalne(TimeInterval i1, TimeInterval i2); +extern bool tintervallt(TimeInterval i1, TimeInterval i2); +extern bool tintervalgt(TimeInterval i1, TimeInterval i2); +extern bool tintervalle(TimeInterval i1, TimeInterval i2); +extern bool tintervalge(TimeInterval i1, TimeInterval i2); +extern bool tintervalleneq(TimeInterval i, RelativeTime t); +extern bool tintervallenne(TimeInterval i, RelativeTime t); +extern bool tintervallenlt(TimeInterval i, RelativeTime t); +extern bool tintervallengt(TimeInterval i, RelativeTime t); +extern bool tintervallenle(TimeInterval i, RelativeTime t); +extern bool tintervallenge(TimeInterval i, RelativeTime t); +extern bool tintervalct(TimeInterval i1, TimeInterval i2); +extern bool tintervalov(TimeInterval i1, TimeInterval i2); +extern AbsoluteTime tintervalstart(TimeInterval i); +extern AbsoluteTime tintervalend(TimeInterval i); +extern int32 int4reltime(int32 timevalue); +extern text *timeofday(void); + #endif /* NABSTIME_H */ diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h new file mode 100644 index 0000000000..27a5288cf3 --- /dev/null +++ b/src/include/utils/timestamp.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Definitions for the SQL92 "timestamp" and "interval" types. + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: timestamp.h,v 1.1 2000/02/16 17:26:26 thomas Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef TIMESTAMP_H +#define TIMESTAMP_H + +#include +#include +#include + +/* + * Timestamp represents absolute time. + * Interval represents delta time. Keep track of months (and years) + * separately since the elapsed time spanned is unknown until instantiated + * relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + */ + +typedef double Timestamp; + +typedef struct +{ + double time; /* all time units other than months and + * years */ + int4 month; /* months and years, after time for + * alignment */ +} Interval; + + +#ifdef NAN +#define DT_INVALID (NAN) +#else +#define DT_INVALID (DBL_MIN+DBL_MIN) +#endif +#ifdef HUGE_VAL +#define DT_NOBEGIN (-HUGE_VAL) +#define DT_NOEND (HUGE_VAL) +#else +#define DT_NOBEGIN (-DBL_MAX) +#define DT_NOEND (DBL_MAX) +#endif +#define DT_CURRENT (DBL_MIN) +#define DT_EPOCH (-DBL_MIN) + +#define TIMESTAMP_INVALID(j) {j = DT_INVALID;} +#ifdef NAN +#define TIMESTAMP_IS_INVALID(j) (isnan(j)) +#else +#define TIMESTAMP_IS_INVALID(j) (j == DT_INVALID) +#endif + +#define TIMESTAMP_NOBEGIN(j) {j = DT_NOBEGIN;} +#define TIMESTAMP_IS_NOBEGIN(j) (j == DT_NOBEGIN) + +#define TIMESTAMP_NOEND(j) {j = DT_NOEND;} +#define TIMESTAMP_IS_NOEND(j) (j == DT_NOEND) + +#define TIMESTAMP_CURRENT(j) {j = DT_CURRENT;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_current(double j); + +#define TIMESTAMP_IS_CURRENT(j) timestamp_is_current(j) +#else +#define TIMESTAMP_IS_CURRENT(j) (j == DT_CURRENT) +#endif + +#define TIMESTAMP_EPOCH(j) {j = DT_EPOCH;} +#if defined(linux) && defined(__powerpc__) +extern int timestamp_is_epoch(double j); + +#define TIMESTAMP_IS_EPOCH(j) timestamp_is_epoch(j) +#else +#define TIMESTAMP_IS_EPOCH(j) (j == DT_EPOCH) +#endif + +#define TIMESTAMP_IS_RELATIVE(j) (TIMESTAMP_IS_CURRENT(j) || TIMESTAMP_IS_EPOCH(j)) +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_INVALID(j) \ + || TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) +#define TIMESTAMP_IS_RESERVED(j) (TIMESTAMP_IS_RELATIVE(j) || TIMESTAMP_NOT_FINITE(j)) + +#define INTERVAL_INVALID(j) {(j).time = DT_INVALID;} +#ifdef NAN +#define INTERVAL_IS_INVALID(j) (isnan((j).time)) +#else +#define INTERVAL_IS_INVALID(j) ((j).time == DT_INVALID) +#endif +#define INTERVAL_NOT_FINITE(j) INTERVAL_IS_INVALID(j) + +#define TIME_PREC_INV 1000000.0 +#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) + + +#if 0 + + +/* + * Date/time validation + * Include check for leap year. + */ + +extern int day_tab[2][13]; + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* Julian date support for date2j() and j2date() + * Set the minimum year to one greater than the year of the first valid day + * to avoid having to check year and day both. - tgl 97/05/08 + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (23) + +#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ + || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ + || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) + +#define UTIME_MINYEAR (1901) +#define UTIME_MINMONTH (12) +#define UTIME_MINDAY (14) +#define UTIME_MAXYEAR (2038) +#define UTIME_MAXMONTH (01) +#define UTIME_MAXDAY (18) + +#define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \ + || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \ + || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \ + && ((y < UTIME_MAXYEAR) \ + || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \ + || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY)))))) + + +#endif + + +/* + * timestamp.c prototypes + */ + +extern Timestamp *timestamp_in(char *str); +extern char *timestamp_out(Timestamp *dt); +extern bool timestamp_eq(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_ne(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_lt(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_le(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_ge(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_gt(Timestamp *dt1, Timestamp *dt2); +extern bool timestamp_finite(Timestamp *timestamp); +extern int timestamp_cmp(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_smaller(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_larger(Timestamp *dt1, Timestamp *dt2); + +extern Interval *interval_in(char *str); +extern char *interval_out(Interval *span); +extern bool interval_eq(Interval *span1, Interval *span2); +extern bool interval_ne(Interval *span1, Interval *span2); +extern bool interval_lt(Interval *span1, Interval *span2); +extern bool interval_le(Interval *span1, Interval *span2); +extern bool interval_ge(Interval *span1, Interval *span2); +extern bool interval_gt(Interval *span1, Interval *span2); +extern bool interval_finite(Interval *span); +extern int interval_cmp(Interval *span1, Interval *span2); +extern Interval *interval_smaller(Interval *span1, Interval *span2); +extern Interval *interval_larger(Interval *span1, Interval *span2); + +extern text *timestamp_text(Timestamp *timestamp); +extern Timestamp *text_timestamp(text *str); +extern text *interval_text(Interval *interval); +extern Interval *text_interval(text *str); +extern Timestamp *timestamp_trunc(text *units, Timestamp *timestamp); +extern Interval *interval_trunc(text *units, Interval *interval); +extern float64 timestamp_part(text *units, Timestamp *timestamp); +extern float64 interval_part(text *units, Interval *interval); +extern text *timestamp_zone(text *zone, Timestamp *timestamp); + +extern Interval *interval_um(Interval *span); +extern Interval *interval_pl(Interval *span1, Interval *span2); +extern Interval *interval_mi(Interval *span1, Interval *span2); +extern Interval *interval_div(Interval *span1, float8 *arg2); + +extern Interval *timestamp_mi(Timestamp *dt1, Timestamp *dt2); +extern Timestamp *timestamp_pl_span(Timestamp *dt, Interval *span); +extern Timestamp *timestamp_mi_span(Timestamp *dt, Interval *span); +extern Interval *timestamp_age(Timestamp *dt1, Timestamp *dt2); + +extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt); +extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn); + +extern Timestamp SetTimestamp(Timestamp timestamp); +extern Timestamp dt2local(Timestamp dt, int timezone); +extern void dt2time(Timestamp dt, int *hour, int *min, double *sec); +extern int EncodeSpecialTimestamp(Timestamp dt, char *str); +extern int interval2tm(Interval span, struct tm * tm, float8 *fsec); +extern int tm2interval(struct tm * tm, double fsec, Interval *span); +extern Timestamp *now(void); + +#endif /* TIMESTAMP_H */