From 6d5d673ca87903e73cc88bfcf9b7ca3266f6aa99 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Sun, 10 Jan 1999 17:20:54 +0000 Subject: [PATCH] Be more careful to check input string lengths as well as values when deciding whether a field is a year field. Assume *anything* longer than 2 digits (if it isn't a special-case doy) is a valid year. This should fix the "Y1K" and "Y10K" problems pointed out by Massimo recently. Check usage of BC to require a positive-valued year; before just used it to flip the sign of the year without checking. This led to problems near year zero. Allow a 5 digit "concatenated date" of 2 digit year plus day of year. Do 2->4 digit year correction for 6 and 5 digit "concatenated dates". Somehow forgot this originally. Guess not many folks use it... --- src/backend/utils/adt/dt.c | 79 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c index f08d70ccc5..24137d5b31 100644 --- a/src/backend/utils/adt/dt.c +++ b/src/backend/utils/adt/dt.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.60 1998/12/31 16:30:57 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.61 1999/01/10 17:20:54 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -2839,12 +2839,15 @@ DecodeDateTime(char **field, int *ftype, int nf, case DTK_NUMBER: flen = strlen(field[i]); - if (flen > 4) + /* 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) != 0) return -1; } + /* otherwise it is a single date/time field... */ else { if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0) @@ -3000,7 +3003,12 @@ DecodeDateTime(char **field, int *ftype, int nf, /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */ if (bc) - tm->tm_year = -(tm->tm_year - 1); + { + 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); + } if ((mer != HR24) && (tm->tm_hour > 12)) return -1; @@ -3375,8 +3383,23 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask); #endif - /* enough digits to be unequivocal year? */ - if (flen == 4) + /* 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) { #ifdef DATEDEBUG printf("DecodeNumber- match %d (%s) as year\n", val, str); @@ -3399,18 +3422,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double tm->tm_year = val; - /* special case day of year? */ - } - else 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); - - /* already have year? then could be month */ } + /* already have year? then could be month */ else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH))) && ((val >= 1) && (val <= 12))) { @@ -3460,10 +3473,15 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double #endif *tmask = DTK_M(YEAR); tm->tm_year = val; - if (tm->tm_year < 70) - tm->tm_year += 2000; - else if (tm->tm_year < 100) - tm->tm_year += 1900; + + /* adjust ONLY if exactly two digits... */ + if (flen == 2) + { + if (tm->tm_year < 70) + tm->tm_year += 2000; + else if (tm->tm_year < 100) + tm->tm_year += 1900; + } } else @@ -3527,9 +3545,30 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou tm->tm_mon = atoi(str + 2); *(str + 2) = '\0'; tm->tm_year = atoi(str + 0); + + if (tm->tm_year < 70) + tm->tm_year += 2000; + else if (tm->tm_year < 100) + tm->tm_year += 1900; } } + else if ((len == 5) && !(fmask & DTK_DATE_M)) + { +#ifdef DATEDEBUG + printf("DecodeNumberField- %s is 5 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask); +#endif + *tmask = DTK_DATE_M; + tm->tm_mday = atoi(str + 2); + *(str + 2) = '\0'; + tm->tm_mon = 1; + tm->tm_year = atoi(str + 0); + + if (tm->tm_year < 70) + tm->tm_year += 2000; + else if (tm->tm_year < 100) + tm->tm_year += 1900; + } else if (strchr(str, '.') != NULL) { #ifdef DATEDEBUG -- GitLab