diff options
Diffstat (limited to 'src/backend/utils/adt/nabstime.c')
-rw-r--r-- | src/backend/utils/adt/nabstime.c | 877 |
1 files changed, 221 insertions, 656 deletions
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 83858920780..e678805c989 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.13 1997/01/27 01:51:21 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.14 1997/03/14 23:20:31 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -22,494 +22,174 @@ #endif #include "access/xact.h" -#define MAXDATEFIELDS 25 - -#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\t') - -/* this is fast but dirty. note the return's in the middle. */ -#define GOBBLE_NUM(cp, c, x, ip) \ - (c) = *(cp)++; \ - if ((c) < '0' || (c) > '9') \ - return -1; /* missing digit */ \ - (x) = (c) - '0'; \ - (c) = *(cp)++; \ - if ((c) >= '0' && (c) <= '9') { \ - (x) = 10*(x) + (c) - '0'; \ - (c) = *(cp)++; \ - } \ - if ((c) != ':' && (c) != '\0' && !ISSPACE(c)) \ - return -1; /* missing colon */ \ - *(ip) = (x) /* N.B.: no semi-colon here */ - -#define EPOCH 1970 -#define DAYS_PER_400YRS (time_t)146097 -#define DAYS_PER_4YRS (time_t)1461 -#define SECS_PER_DAY 86400 -#define SECS_PER_HOUR 3600 -#define DIVBY4(n) ((n) >> 2) -#define YRNUM(c, y) (DIVBY4(DAYS_PER_400YRS*(c)) + DIVBY4(DAYS_PER_4YRS*(y))) -#define DAYNUM(c,y,mon,d) (YRNUM((c), (y)) + mdays[mon] + (d)) -#define EPOCH_DAYNUM DAYNUM(19, 69, 10, 1) /* really January 1, 1970 */ +#if USE_EURODATES +extern int EuroDates; +#endif + +#if FALSE +#define MAXDATELEN 47 +#define MAXDATEFIELDS 25 +#endif + #define MIN_DAYNUM -24856 /* December 13, 1901 */ #define MAX_DAYNUM 24854 /* January 18, 2038 */ -/* definitions for squeezing values into "value" */ -#define ABS_SIGNBIT 0200 -#define VALMASK 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)) -#define IsLeapYear(yr) ((yr%4) == 0) - -char nmdays[] = { - 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; -/* days since start of year. mdays[0] is March, mdays[11] is February */ -static short mdays[] = { - 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 -}; - -/* exports */ -static int dtok_numparsed; - -/* - * 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 NUL-terminated. - */ -static datetkn datetktbl[] = { -/* text token lexval */ -{ "acsst", DTZ, 63}, /* Cent. Australia */ -{ "acst", TZ, 57}, /* Cent. Australia */ -{ "adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */ -{ "aesst", DTZ, 66}, /* E. Australia */ -{ "aest", TZ, 60}, /* Australia Eastern Std Time */ -{ "ahst", TZ, 60}, /* Alaska-Hawaii Std Time */ -{ "am", AMPM, AM}, -{ "apr", MONTH, 4}, -{ "april", MONTH, 4}, -{ "ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */ -{ "at", PG_IGNORE, 0}, /* "at" (throwaway) */ -{ "aug", MONTH, 8}, -{ "august", MONTH, 8}, -{ "awsst", DTZ, 54}, /* W. Australia */ -{ "awst", TZ, 48}, /* W. Australia */ -{ "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 */ -{ "cst", TZ, NEG(36)}, /* Central Standard Time */ -{ "dec", MONTH, 12}, -{ "decemb", MONTH, 12}, -{ "dnt", TZ, 6}, /* Dansk Normal Tid */ -{ "dst", PG_IGNORE, 0}, -{ "east", TZ, NEG(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 */ -{ "est", TZ, NEG(30)}, /* Eastern Standard Time */ -{ "feb", MONTH, 2}, -{ "februa", MONTH, 2}, -{ "fri", PG_IGNORE, 5}, -{ "friday", PG_IGNORE, 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 */ -{ "ist", TZ, 12}, /* Israel */ -{ "it", TZ, 22}, /* Iran Time */ -{ "jan", MONTH, 1}, -{ "januar", 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", PG_IGNORE, 1}, -{ "monday", PG_IGNORE, 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}, -{ "novemb", MONTH, 11}, -{ "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}, -{ "octobe", MONTH, 10}, -{ "on", PG_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", PG_IGNORE, 6}, -{ "saturd", PG_IGNORE, 6}, -{ "sep", MONTH, 9}, -{ "sept", MONTH, 9}, -{ "septem", MONTH, 9}, -{ "set", TZ, NEG(6)}, /* Seychelles Time ?? */ -{ "sst", DTZ, 12}, /* Swedish Summer Time */ -{ "sun", PG_IGNORE, 0}, -{ "sunday", PG_IGNORE, 0}, -{ "swt", TZ, 6}, /* Swedish Winter Time */ -{ "thu", PG_IGNORE, 4}, -{ "thur", PG_IGNORE, 4}, -{ "thurs", PG_IGNORE, 4}, -{ "thursd", PG_IGNORE, 4}, -{ "tue", PG_IGNORE, 2}, -{ "tues", PG_IGNORE, 2}, -{ "tuesda", PG_IGNORE, 2}, -{ "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", PG_IGNORE, 3}, -{ "wednes", PG_IGNORE, 3}, -{ "weds", PG_IGNORE, 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 */ -{ "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. */ -}; - -static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]; /* * parse and convert absolute date in timestr (the normal interface) * * Returns the number of seconds since epoch (January 1 1970 GMT) */ + +#ifndef USE_POSIX_TIME +long int timezone; +long int daylight; +#endif + AbsoluteTime -nabstimein(char* timestr) +GetCurrentAbsoluteTime(void) { - int tz = 0; - struct tm date; - - if (!timestr) - return INVALID_ABSTIME; - while (ISSPACE(*timestr)) - ++timestr; - - if (!strcasecmp(timestr, "epoch")) - return EPOCH_ABSTIME; - if (!strcasecmp(timestr, "now")) - return GetCurrentTransactionStartTime(); - if (!strcasecmp(timestr, "current")) - return CURRENT_ABSTIME; - if (!strcasecmp(timestr, "infinity")) - return NOEND_ABSTIME; - if (!strcasecmp(timestr, "-infinity")) - return NOSTART_ABSTIME; - if (prsabsdate(timestr, &date, &tz) < 0) - return INVALID_ABSTIME; - return dateconv(&date, tz); -} + time_t now; -/* - * just parse the absolute date in timestr and get back a broken-out date. - */ -int -prsabsdate(char *timestr, - struct tm *tm, - int *tzp) /* - minutes west */ -{ - register int nf; - char *fields[MAXDATEFIELDS]; - static char delims[] = "- \t\n/,"; - - nf = split(timestr, fields, MAXDATEFIELDS, delims+1); - if (nf > MAXDATEFIELDS) - return -1; - if (tryabsdate(fields, nf, tm, tzp) < 0) { - register char *p = timestr; - - /* - * could be a DEC-date; glue it all back together, split it - * with dash as a delimiter and try again. Yes, this is a - * hack, but so are DEC-dates. - */ - while (--nf > 0) { - while (*p++ != '\0') - ; - p[-1] = ' '; - } - nf = split(timestr, fields, MAXDATEFIELDS, delims); - if (nf > MAXDATEFIELDS) - return -1; - if (tryabsdate(fields, nf, tm, tzp) < 0) - return -1; - } - return 0; -} +#ifdef USE_POSIX_TIME + now = time(NULL); -/* - * try to parse pre-split timestr as an absolute date - */ -int -tryabsdate(char *fields[], int nf, struct tm *tm, int *tzp) -{ - register int i; - register datetkn *tp; - register long flg = 0, ty; - int mer = HR24, bigval = -1; -#ifndef USE_POSIX_TIME - struct timeb now; /* the old V7-ism */ - - (void) ftime(&now); - *tzp = now.timezone; -#else /* USE_POSIX_TIME */ #if defined(HAVE_TZSET) && defined(HAVE_INT_TIMEZONE) - tzset(); -#ifndef win32 - *tzp = timezone / 60; /* this is an X/Open-ism */ -#else - *tzp = _timezone / 60; /* this is an X/Open-ism */ -#endif /* win32 */ + tzset(); #else /* !HAVE_TZSET */ - time_t now = time((time_t *) NULL); struct tm *tmnow = localtime(&now); - - *tzp = - tmnow->tm_gmtoff / 60; /* tm_gmtoff is Sun/DEC-ism */ + + timezone = - tmnow->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */ + daylight = (tmnow->tm_isdst > 0); #endif + +#else /* ! USE_POSIX_TIME */ + struct timeb tbnow; /* the old V7-ism */ + + (void) ftime(&tbnow); + now = tbnow.time; + timezone = tbnow.timezone * 60; + daylight = (tbnow.dstflag != 0); #endif - - tm->tm_mday = tm->tm_mon = tm->tm_year = -1; /* mandatory */ - tm->tm_hour = tm->tm_min = tm->tm_sec = 0; - tm->tm_isdst = -1; /* assume we don't know. */ - dtok_numparsed = 0; - - for (i = 0; i < nf; i++) { - if (fields[i][0] == '\0') - continue; - tp = datetoktype(fields[i], &bigval); - ty = (1L << tp->type) & ~(1L << PG_IGNORE); - if (flg&ty) - return -1; /* repeated type */ - flg |= ty; - switch (tp->type) { - case YEAR: - tm->tm_year = bigval; - break; - case DAY: - tm->tm_mday = bigval; - break; - case MONTH: - tm->tm_mon = tp->value; - break; - case TIME: - if (parsetime(fields[i], tm) < 0) - return -1; - break; - case DTZ: - tm->tm_isdst++; - /* FALLTHROUGH */ - case TZ: - *tzp = FROMVAL(tp); - break; - case PG_IGNORE: - break; - case AMPM: - mer = tp->value; - break; - default: - return -1; /* bad token type: CANTHAPPEN */ - } - } - if (tm->tm_year == -1 || tm->tm_mon == -1 || tm->tm_mday == -1) - return -1; /* missing component */ - if (mer == PM) - tm->tm_hour += 12; - return 0; -} + + return((AbsoluteTime) now); +} /* GetCurrentAbsoluteTime() */ -/* return -1 on failure */ -int -parsetime(char *time, struct tm *tm) +void +GetCurrentTime(struct tm *tm) { - register char c; - register int x; - - tm->tm_sec = 0; - GOBBLE_NUM(time, c, x, &tm->tm_hour); - if (c != ':') - return -1; /* only hour; too short */ - GOBBLE_NUM(time, c, x, &tm->tm_min); - if (c != ':') - return 0; /* no seconds; okay */ - GOBBLE_NUM(time, c, x, &tm->tm_sec); - /* this may be considered too strict. garbage at end of time? */ - return (c == '\0' || ISSPACE(c)? 0: -1); -} + time_t now; + struct tm *tt; + now = GetCurrentTransactionStartTime(); + tt = gmtime( &now); -/* - * split - divide a string into fields, like awk split() + tm->tm_year = tt->tm_year+1900; + tm->tm_mon = tt->tm_mon+1; + tm->tm_mday = tt->tm_mday; + tm->tm_hour = tt->tm_hour; + tm->tm_min = tt->tm_min; + tm->tm_sec = tt->tm_sec; + tm->tm_isdst = tt->tm_isdst; + + return; +} /* GetCurrentTime() */ + + +/* nabstimein() + * Decode date/time string and return abstime. */ -int /* number of fields, including overflow */ -split(char *string, - char *fields[], /* list is not NULL-terminated */ - int nfields, /* number of entries available in fields[] */ - char *sep) /* "" white, "c" single char, "ab" [ab]+ */ +AbsoluteTime +nabstimein(char* str) { - register char *p = string; - register char c; /* latest character */ - register char sepc = sep[0]; - register char sepc2; - register int fn; - register char **fp = fields; - register char *sepp; - register int trimtrail; - - /* white space */ - if (sepc == '\0') { - while ((c = *p++) == ' ' || c == '\t') - continue; - p--; - trimtrail = 1; - sep = " \t"; /* note, code below knows this is 2 long */ - sepc = ' '; - } else - trimtrail = 0; - sepc2 = sep[1]; /* now we can safely pick this up */ - - /* catch empties */ - if (*p == '\0') - return(0); - - /* single separator */ - if (sepc2 == '\0') { - fn = nfields; - for (;;) { - *fp++ = p; - fn--; - if (fn == 0) - break; - while ((c = *p++) != sepc) - if (c == '\0') - return(nfields - fn); - *(p-1) = '\0'; - } - /* we have overflowed the fields vector -- just count them */ - fn = nfields; - for (;;) { - while ((c = *p++) != sepc) - if (c == '\0') - return(fn); - fn++; - } - /* not reached */ - } - - /* two separators */ - if (sep[2] == '\0') { - fn = nfields; - for (;;) { - *fp++ = p; - fn--; - while ((c = *p++) != sepc && c != sepc2) - if (c == '\0') { - if (trimtrail && **(fp-1) == '\0') - fn++; - return(nfields - fn); - } - if (fn == 0) - break; - *(p-1) = '\0'; - while ((c = *p++) == sepc || c == sepc2) - continue; - p--; - } - /* we have overflowed the fields vector -- just count them */ - fn = nfields; - while (c != '\0') { - while ((c = *p++) == sepc || c == sepc2) - continue; - p--; - fn++; - while ((c = *p++) != '\0' && c != sepc && c != sepc2) - continue; - } - /* might have to trim trailing white space */ - if (trimtrail) { - p--; - while ((c = *--p) == sepc || c == sepc2) - continue; - p++; - if (*p != '\0') { - if (fn == nfields+1) - *p = '\0'; - fn--; - } - } - return(fn); - } - - /* n separators */ - fn = 0; - for (;;) { - if (fn < nfields) - *fp++ = p; - fn++; - for (;;) { - c = *p++; - if (c == '\0') - return(fn); - sepp = sep; - while ((sepc = *sepp++) != '\0' && sepc != c) - continue; - if (sepc != '\0') /* it was a separator */ - break; - } - if (fn < nfields) - *(p-1) = '\0'; - for (;;) { - c = *p++; - sepp = sep; - while ((sepc = *sepp++) != '\0' && sepc != c) - continue; - if (sepc == '\0') /* it wasn't a separator */ - break; - } - p--; - } - - /* not reached */ -} + int sec; + double fsec; + int day, tz = 0; + struct tm date, *tm = &date; + + char *field[MAXDATEFIELDS]; + char lowstr[MAXDATELEN+1]; + int dtype; + int nf, ftype[MAXDATEFIELDS]; + + if (!PointerIsValid(str)) + elog(WARN,"Bad (null) abstime external representation",NULL); + + if (strlen(str) > MAXDATELEN) + elog( WARN, "Bad (length) abstime external representation '%s'",str); + + if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0) + || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tz) != 0)) + elog( WARN, "Bad abstime external representation '%s'",str); + +#ifdef DATEDEBUG +printf( "nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE); +#endif + + switch (dtype) { + case DTK_DATE: +#if FALSE + return(dateconv( &date, tz)); +#endif + /* validate, before going out of range on some members */ + if (tm->tm_year < 1901 || tm->tm_year > 2038 + || tm->tm_mon < 1 || tm->tm_mon > 12 + || tm->tm_mday < 1 || tm->tm_mday > 31 + || tm->tm_hour < 0 || tm->tm_hour >= 24 + || tm->tm_min < 0 || tm->tm_min > 59 + || tm->tm_sec < 0 || tm->tm_sec > 59) + return INVALID_ABSTIME; + + day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1)); + + /* check for time out of range */ + if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM)) + return INVALID_ABSTIME; + + /* convert to seconds */ + sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60; + + /* check for overflow */ + if ((day == MAX_DAYNUM && sec < 0) || + (day == MIN_DAYNUM && sec > 0)) + return INVALID_ABSTIME; + + /* daylight correction */ + if (tm->tm_isdst < 0) { /* unknown; find out */ + tm->tm_isdst = (daylight > 0); + }; + if (tm->tm_isdst > 0) + sec -= 60*60; + + /* check for reserved values (e.g. "current" on edge of usual range */ + if (!AbsoluteTimeIsReal(sec)) + return INVALID_ABSTIME; + + return sec; + + case DTK_EPOCH: + return EPOCH_ABSTIME; + + case DTK_CURRENT: + return CURRENT_ABSTIME; + + case DTK_LATE: + return NOEND_ABSTIME; + + case DTK_EARLY: + return NOSTART_ABSTIME; + + case DTK_INVALID: + return INVALID_ABSTIME; + + default: + }; + + elog(WARN,"Bad abstime (internal coding error) '%s'",str); + return INVALID_ABSTIME; +} /* nabstimein() */ + /* * Given an AbsoluteTime return the English text version of the date @@ -529,11 +209,11 @@ nabstimeout(AbsoluteTime time) char* result; switch (time) { - case EPOCH_ABSTIME: (void) strcpy(buf, "epoch"); break; - case INVALID_ABSTIME: (void) strcpy(buf, "Invalid Abstime"); break; - case CURRENT_ABSTIME: (void) strcpy(buf, "current"); break; - case NOEND_ABSTIME: (void) strcpy(buf, "infinity"); break; - case NOSTART_ABSTIME: (void) strcpy(buf, "-infinity"); break; + case EPOCH_ABSTIME: (void) strcpy(buf, EPOCH); break; + case INVALID_ABSTIME: (void) strcpy(buf, INVALID); break; + case CURRENT_ABSTIME: (void) strcpy(buf, DCURRENT); break; + case NOEND_ABSTIME: (void) strcpy(buf, LATE); break; + case NOSTART_ABSTIME: (void) strcpy(buf, EARLY); break; default: /* hack -- localtime happens to work for negative times */ (void) strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z", @@ -545,25 +225,36 @@ nabstimeout(AbsoluteTime time) return result; } + /* turn a (struct tm) and a few variables into a time_t, with range checking */ AbsoluteTime dateconv(register struct tm *tm, int zone) { tm->tm_wday = tm->tm_yday = 0; - + +#if FALSE + if (tm->tm_year < 70) { + tm->tm_year += 2000; + } else if (tm->tm_year < 1000) { + tm->tm_year += 1900; + }; +#endif + /* validate, before going out of range on some members */ - if (tm->tm_year < 0 || tm->tm_mon < 1 || tm->tm_mon > 12 || - tm->tm_mday < 1 || tm->tm_hour < 0 || tm->tm_hour >= 24 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 59) - return -1; - + if (tm->tm_year < 1901 || tm->tm_year > 2038 + || tm->tm_mon < 1 || tm->tm_mon > 12 + || tm->tm_mday < 1 || tm->tm_mday > 31 + || tm->tm_hour < 0 || tm->tm_hour >= 24 + || tm->tm_min < 0 || tm->tm_min > 59 + || tm->tm_sec < 0 || tm->tm_sec > 59) + return INVALID_ABSTIME; + /* * zone should really be -zone, and tz should be set to tp->value, not * -tp->value. Or the table could be fixed. */ - tm->tm_min += zone; /* mktime lets it be out of range */ - + tm->tm_sec += zone; /* mktime lets it be out of range */ + /* convert to seconds */ return qmktime(tm); } @@ -575,201 +266,78 @@ dateconv(register struct tm *tm, int zone) * and tm_yday. */ time_t -qmktime(struct tm *tp) +qmktime(struct tm *tm) { - register int mon = tp->tm_mon; - register int day = tp->tm_mday, year = tp->tm_year; - register time_t daynum; - time_t secondnum; - register int century; - + time_t sec; + + int day; + +#if FALSE /* If it was a 2 digit year */ - if (year < 100) - year += 1900; - - /* - * validate day against days-per-month table, with leap-year - * correction - */ - if (day > nmdays[mon]) - if (mon != 2 || - (year % 4 == 0 && - ((year % 100 != 0 || year % 400 == 0)) && day > 29)) - return -1; /* day too large for month */ - - /* split year into century and year-of-century */ - century = year / 100; - year %= 100; - /* - * We calculate the day number exactly, assuming the calendar has - * always had the current leap year rules. (The leap year rules are - * to compensate for the fact that the Earth's revolution around the - * Sun takes 365.2425 days). We first need to rotate months so March - * is 0, since we want the last month to have the reduced number of - * days. - */ - if (mon > 2) - mon -= 3; - else { - mon += 9; - if (year == 0) { - century--; - year = 99; - } else - --year; - } - daynum = -EPOCH_DAYNUM + DAYNUM(century, year, mon, day); - + if (tm->tm_year < 100) + tm->tm_year += 1900; +#endif + + day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1)); + /* check for time out of range */ - if (daynum < MIN_DAYNUM || daynum > MAX_DAYNUM) + if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM)) return INVALID_ABSTIME; - + /* convert to seconds */ - secondnum = - tp->tm_sec + (tp->tm_min +(daynum*24 + tp->tm_hour)*60)*60; - + sec = tm->tm_sec + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60; + /* check for overflow */ - if ((daynum == MAX_DAYNUM && secondnum < 0) || - (daynum == MIN_DAYNUM && secondnum > 0)) + if ((day == MAX_DAYNUM && sec < 0) || + (day == MIN_DAYNUM && sec > 0)) return INVALID_ABSTIME; - - /* check for "current", "infinity", "-infinity" */ - if (!AbsoluteTimeIsReal(secondnum)) + + /* check for reserved values (e.g. "current" on edge of usual range */ + if (!AbsoluteTimeIsReal(sec)) return INVALID_ABSTIME; - - /* daylight correction */ - if (tp->tm_isdst < 0) /* unknown; find out */ - { - struct tm *result; - - /* NT returns NULL for any time before 1/1/70 */ - result = localtime(&secondnum); - if (result == NULL) - return INVALID_ABSTIME; - else - tp->tm_isdst = result->tm_isdst; - } - if (tp->tm_isdst > 0) - secondnum -= 60*60; - - return secondnum; -} -datetkn * -datetoktype(char *s, int *bigvalp) -{ - register char *cp = s; - register char c = *cp; - static datetkn t; - register datetkn *tp = &t; - - if (isascii(c) && isdigit(c)) { - register int len = strlen(cp); - - if (len > 3 && (cp[1] == ':' || cp[2] == ':')) - tp->type = TIME; - else { - if (bigvalp != NULL) - /* won't fit in tp->value */ - *bigvalp = atoi(cp); - if (len == 4) - tp->type = YEAR; - else if (++dtok_numparsed == 1) - tp->type = DAY; - else - tp->type = YEAR; - } - } else if (c == '-' || c == '+') { - register int val = atoi(cp + 1); - register int hr = val / 100; - register int min = val % 100; - - val = hr*60 + min; - if (c == '-') - val = -val; - tp->type = TZ; - TOVAL(tp, val); - } else { - char lowtoken[TOKMAXLEN+1]; - register char *ltp = lowtoken, *endltp = lowtoken+TOKMAXLEN; - - /* copy to lowtoken to avoid modifying s */ - while ((c = *cp++) != '\0' && ltp < endltp) - *ltp++ = (isascii(c) && isupper(c)? tolower(c): c); - *ltp = '\0'; - tp = datebsearch(lowtoken, datetktbl, szdatetktbl); - if (tp == NULL) { - tp = &t; - tp->type = PG_IGNORE; - } - } - return tp; -} + /* daylight correction */ + if (tm->tm_isdst < 0) { /* unknown; find out */ + tm->tm_isdst = (daylight > 0); + }; + if (tm->tm_isdst > 0) + sec -= 60*60; -/* - * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this - * is WAY faster than the generic bsearch(). - */ -datetkn * -datebsearch(char *key, datetkn *base, unsigned int nel) -{ - register datetkn *last = base + nel - 1, *position; - register 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 0; -} + return sec; +} /* qmktime() */ /* * AbsoluteTimeIsBefore -- true iff time1 is before time2. + * AbsoluteTimeIsBefore -- true iff time1 is after time2. */ - bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2) { - AbsoluteTime tm = GetCurrentTransactionStartTime(); - Assert(AbsoluteTimeIsValid(time1)); Assert(AbsoluteTimeIsValid(time2)); - - if ((time1 == CURRENT_ABSTIME) || (time2 == CURRENT_ABSTIME)) - return false; + if (time1 == CURRENT_ABSTIME) - return (tm < time2); + time1 = GetCurrentTransactionStartTime(); + if (time2 == CURRENT_ABSTIME) - return (time1 < tm); - + time2 = GetCurrentTransactionStartTime(); + return (time1 < time2); } bool AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2) { - AbsoluteTime tm = GetCurrentTransactionStartTime(); - Assert(AbsoluteTimeIsValid(time1)); Assert(AbsoluteTimeIsValid(time2)); - - if ((time1 == CURRENT_ABSTIME) || (time2 == CURRENT_ABSTIME)) - return false; + if (time1 == CURRENT_ABSTIME) - return (tm > time2); + time1 = GetCurrentTransactionStartTime(); + if (time2 == CURRENT_ABSTIME) - return (time1 > tm); - + time2 = GetCurrentTransactionStartTime(); + return (time1 > time2); } @@ -781,9 +349,8 @@ AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2) * abstimegt - returns 1, iff t1 greater than t2 * abstimele - returns 1, iff t1 less than or equal to t2 * abstimege - returns 1, iff t1 greater than or equal to t2 - * */ -int32 +bool abstimeeq(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -792,11 +359,11 @@ abstimeeq(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 == t2); } -int32 +bool abstimene(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -805,11 +372,11 @@ abstimene(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 != t2); } -int32 +bool abstimelt(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -818,11 +385,11 @@ abstimelt(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 < t2); } -int32 +bool abstimegt(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -831,11 +398,11 @@ abstimegt(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 > t2); } -int32 +bool abstimele(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -844,11 +411,11 @@ abstimele(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 <= t2); } -int32 +bool abstimege(AbsoluteTime t1, AbsoluteTime t2) { if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME) @@ -857,8 +424,6 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2) t1 = GetCurrentTransactionStartTime(); if (t2 == CURRENT_ABSTIME) t2 = GetCurrentTransactionStartTime(); - + return(t1 >= t2); } - - |