Commit 1ace93c4 authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Fix "Y-2K" problem with two-digit BC dates being corrected by two millenia.

 They are not corrected now.
Allow the date type to accept BC dates.
Share more date/time validation declarations through dt.h.
parent 791822e3
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.26 1998/12/31 16:30:56 thomas Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.27 1999/01/20 16:29:39 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,12 +27,13 @@ ...@@ -27,12 +27,13 @@
static int date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn); static int date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn);
#if 0
static int day_tab[2][12] = { static int day_tab[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
#define isleap(y) (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0) #define isleap(y) (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0)
#endif
#define UTIME_MINYEAR (1901) #define UTIME_MINYEAR (1901)
#define UTIME_MINMONTH (12) #define UTIME_MINMONTH (12)
...@@ -99,10 +100,12 @@ date_in(char *str) ...@@ -99,10 +100,12 @@ date_in(char *str)
elog(ERROR, "Unrecognized date external representation %s", str); elog(ERROR, "Unrecognized date external representation %s", str);
} }
#if 0
if (tm->tm_year < 0 || tm->tm_year > 32767) if (tm->tm_year < 0 || tm->tm_year > 32767)
elog(ERROR, "date_in: year must be limited to values 0 through 32767 in '%s'", str); elog(ERROR, "date_in: year must be limited to values 0 through 32767 in '%s'", str);
if (tm->tm_mon < 1 || tm->tm_mon > 12) if (tm->tm_mon < 1 || tm->tm_mon > 12)
elog(ERROR, "date_in: month must be limited to values 1 through 12 in '%s'", str); elog(ERROR, "date_in: month must be limited to values 1 through 12 in '%s'", str);
#endif
if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
elog(ERROR, "date_in: day must be limited to values 1 through %d in '%s'", elog(ERROR, "date_in: day must be limited to values 1 through %d in '%s'",
day_tab[isleap(tm->tm_year)][tm->tm_mon - 1], str); day_tab[isleap(tm->tm_year)][tm->tm_mon - 1], str);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.61 1999/01/10 17:20:54 thomas Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.62 1999/01/20 16:29:39 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,11 +31,12 @@ ...@@ -31,11 +31,12 @@
#endif #endif
#include "utils/builtins.h" #include "utils/builtins.h"
static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm); static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
static int DecodeNumber(int flen, char *field, static int DecodeNumber(int flen, char *field,
int fmask, int *tmask, struct tm * tm, double *fsec); int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits);
static int DecodeNumberField(int len, char *str, static int DecodeNumberField(int len, char *str,
int fmask, int *tmask, struct tm * tm, double *fsec); int fmask, int *tmask, struct tm * tm, double *fsec, int *is2digits);
static int DecodeSpecial(int field, char *lowtoken, int *val); static int DecodeSpecial(int field, char *lowtoken, int *val);
static int DecodeTime(char *str, int fmask, int *tmask, static int DecodeTime(char *str, int fmask, int *tmask,
struct tm * tm, double *fsec); struct tm * tm, double *fsec);
...@@ -50,12 +51,20 @@ static double time2t(const int hour, const int min, const double sec); ...@@ -50,12 +51,20 @@ static double time2t(const int hour, const int min, const double sec);
static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec); static int timespan2tm(TimeSpan span, struct tm * tm, float8 *fsec);
static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span); static int tm2timespan(struct tm * tm, double fsec, TimeSpan *span);
#define USE_DATE_CACHE 1 #define USE_DATE_CACHE 1
#define ROUND_ALL 0 #define ROUND_ALL 0
#if 0
#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) #define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
#endif
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", char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
...@@ -873,6 +882,7 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span) ...@@ -873,6 +882,7 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
} }
/* adjust for end of month boundary problems... */ /* adjust for end of month boundary problems... */
#if 0
if (tm->tm_mday > mdays[tm->tm_mon - 1]) if (tm->tm_mday > mdays[tm->tm_mon - 1])
{ {
if ((tm->tm_mon == 2) && isleap(tm->tm_year)) if ((tm->tm_mon == 2) && isleap(tm->tm_year))
...@@ -880,6 +890,9 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span) ...@@ -880,6 +890,9 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
else else
tm->tm_mday = mdays[tm->tm_mon - 1]; tm->tm_mday = mdays[tm->tm_mon - 1];
} }
#endif
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]);
#ifdef DATEDEBUG #ifdef DATEDEBUG
printf("datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d\n", printf("datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d\n",
...@@ -1184,16 +1197,22 @@ datetime_age(DateTime *datetime1, DateTime *datetime2) ...@@ -1184,16 +1197,22 @@ datetime_age(DateTime *datetime1, DateTime *datetime2)
{ {
if (dt1 < dt2) if (dt1 < dt2)
{ {
#if 0
tm->tm_mday += mdays[tm1->tm_mon - 1]; tm->tm_mday += mdays[tm1->tm_mon - 1];
if (isleap(tm1->tm_year) && (tm1->tm_mon == 2)) if (isleap(tm1->tm_year) && (tm1->tm_mon == 2))
tm->tm_mday++; tm->tm_mday++;
#endif
tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
tm->tm_mon--; tm->tm_mon--;
} }
else else
{ {
#if 0
tm->tm_mday += mdays[tm2->tm_mon - 1]; tm->tm_mday += mdays[tm2->tm_mon - 1];
if (isleap(tm2->tm_year) && (tm2->tm_mon == 2)) if (isleap(tm2->tm_year) && (tm2->tm_mon == 2))
tm->tm_mday++; tm->tm_mday++;
#endif
tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
tm->tm_mon--; tm->tm_mon--;
} }
} }
...@@ -2036,7 +2055,7 @@ static datetkn datetktbl[] = { ...@@ -2036,7 +2055,7 @@ static datetkn datetktbl[] = {
{"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */ {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
{"aesst", DTZ, 66}, /* E. Australia */ {"aesst", DTZ, 66}, /* E. Australia */
{"aest", TZ, 60}, /* Australia Eastern Std Time */ {"aest", TZ, 60}, /* Australia Eastern Std Time */
{"ahst", TZ, 60}, /* Alaska-Hawaii Std Time */ {"ahst", TZ, NEG(60)}, /* Alaska-Hawaii Std Time */
{"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */ {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
{"am", AMPM, AM}, {"am", AMPM, AM},
{"apr", MONTH, 4}, {"apr", MONTH, 4},
...@@ -2087,12 +2106,12 @@ static datetkn datetktbl[] = { ...@@ -2087,12 +2106,12 @@ static datetkn datetktbl[] = {
{"hmt", DTZ, 18}, /* Hellas ? ? */ {"hmt", DTZ, 18}, /* Hellas ? ? */
{"hst", TZ, NEG(60)}, /* Hawaii Std Time */ {"hst", TZ, NEG(60)}, /* Hawaii Std Time */
{"idle", TZ, 72}, /* Intl. Date Line, East */ {"idle", TZ, 72}, /* Intl. Date Line, East */
{"idlw", TZ, NEG(72)}, /* Intl. Date Line,, est */ {"idlw", TZ, NEG(72)}, /* Intl. Date Line, West */
{LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */ {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
{INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid {INVALID, RESERV, DTK_INVALID},
* time */ /* "invalid" reserved for invalid time */
{"ist", TZ, 12}, /* Israel */ {"ist", TZ, 12}, /* Israel */
{"it", TZ, 22}, /* Iran Time */ {"it", TZ, 21}, /* Iran Time */
{"jan", MONTH, 1}, {"jan", MONTH, 1},
{"january", MONTH, 1}, {"january", MONTH, 1},
{"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */ {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
...@@ -2283,6 +2302,8 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL}; ...@@ -2283,6 +2302,8 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
* These routines will be used by other date/time packages - tgl 97/02/25 * These routines will be used by other date/time packages - tgl 97/02/25
*/ */
#if 0
XXX moved to dt.h - thomas 1999-01-15
/* Set the minimum year to one greater than the year of the first valid day /* 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 * to avoid having to check year and day both. - tgl 97/05/08
*/ */
...@@ -2294,6 +2315,7 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL}; ...@@ -2294,6 +2315,7 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
#define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \ #define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
|| ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \ || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
|| ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY))))) || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
#endif
int int
date2j(int y, int m, int d) date2j(int y, int m, int d)
...@@ -2792,6 +2814,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -2792,6 +2814,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
int flen, int flen,
val; val;
int mer = HR24; int mer = HR24;
int is2digits = FALSE;
int bc = FALSE; int bc = FALSE;
*dtype = DTK_DATE; *dtype = DTK_DATE;
...@@ -2843,14 +2866,14 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -2843,14 +2866,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
* then interpret as a concatenated date or time... */ * then interpret as a concatenated date or time... */
if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M))) if ((flen > 4) && !((fmask & DTK_DATE_M) && (fmask & DTK_TIME_M)))
{ {
if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0) if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
return -1; return -1;
} }
/* otherwise it is a single date/time field... */ /* otherwise it is a single date/time field... */
else else
{ {
if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0) if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
return -1; return -1;
} }
break; break;
...@@ -3009,6 +3032,13 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -3009,6 +3032,13 @@ DecodeDateTime(char **field, int *ftype, int nf,
else else
elog(ERROR,"Inconsistant use of year %04d and 'BC'", tm->tm_year); 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)) if ((mer != HR24) && (tm->tm_hour > 12))
return -1; return -1;
...@@ -3083,6 +3113,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou ...@@ -3083,6 +3113,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
int i; int i;
int flen, int flen,
val; val;
int is2digits = FALSE;
int mer = HR24; int mer = HR24;
*dtype = DTK_TIME; *dtype = DTK_TIME;
...@@ -3110,7 +3141,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou ...@@ -3110,7 +3141,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
case DTK_NUMBER: case DTK_NUMBER:
flen = strlen(field[i]); flen = strlen(field[i]);
if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0) if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
return -1; return -1;
break; break;
...@@ -3209,6 +3240,8 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -3209,6 +3240,8 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
int nf = 0; int nf = 0;
int i, int i,
len; len;
int bc = FALSE;
int is2digits = FALSE;
int type, int type,
val, val,
dmask = 0; dmask = 0;
...@@ -3238,9 +3271,11 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -3238,9 +3271,11 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
nf++; nf++;
} }
#if 0
/* don't allow too many fields */ /* don't allow too many fields */
if (nf > 3) if (nf > 3)
return -1; return -1;
#endif
*tmask = 0; *tmask = 0;
...@@ -3263,6 +3298,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -3263,6 +3298,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
tm->tm_mon = val; tm->tm_mon = val;
break; break;
case ADBC:
bc = (val == BC);
break;
default: default:
#ifdef DATEDEBUG #ifdef DATEDEBUG
printf("DecodeDate- illegal field %s value is %d\n", field[i], val); printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
...@@ -3289,7 +3328,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -3289,7 +3328,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
if ((len = strlen(field[i])) <= 0) if ((len = strlen(field[i])) <= 0)
return -1; return -1;
if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0) if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits) != 0)
return -1; return -1;
if (fmask & dmask) if (fmask & dmask)
...@@ -3299,6 +3338,25 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm) ...@@ -3299,6 +3338,25 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
*tmask |= 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; return 0;
} /* DecodeDate() */ } /* DecodeDate() */
...@@ -3362,7 +3420,8 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec) ...@@ -3362,7 +3420,8 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
* Interpret numeric field as a date value in context. * Interpret numeric field as a date value in context.
*/ */
static int static int
DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec) DecodeNumber(int flen, char *str, int fmask,
int *tmask, struct tm * tm, double *fsec, int *is2digits)
{ {
int val; int val;
char *cp; char *cp;
...@@ -3475,6 +3534,7 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double ...@@ -3475,6 +3534,7 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
tm->tm_year = val; tm->tm_year = val;
/* adjust ONLY if exactly two digits... */ /* adjust ONLY if exactly two digits... */
#if 0
if (flen == 2) if (flen == 2)
{ {
if (tm->tm_year < 70) if (tm->tm_year < 70)
...@@ -3482,6 +3542,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double ...@@ -3482,6 +3542,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
else if (tm->tm_year < 100) else if (tm->tm_year < 100)
tm->tm_year += 1900; tm->tm_year += 1900;
} }
#endif
*is2digits = (flen == 2);
} }
else else
...@@ -3495,7 +3557,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double ...@@ -3495,7 +3557,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
* Interpret numeric string as a concatenated date field. * Interpret numeric string as a concatenated date field.
*/ */
static int static int
DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec) DecodeNumberField(int len, char *str, int fmask,
int *tmask, struct tm * tm, double *fsec, int *is2digits)
{ {
char *cp; char *cp;
...@@ -3546,10 +3609,13 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou ...@@ -3546,10 +3609,13 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou
*(str + 2) = '\0'; *(str + 2) = '\0';
tm->tm_year = atoi(str + 0); tm->tm_year = atoi(str + 0);
#if 0
if (tm->tm_year < 70) if (tm->tm_year < 70)
tm->tm_year += 2000; tm->tm_year += 2000;
else if (tm->tm_year < 100) else if (tm->tm_year < 100)
tm->tm_year += 1900; tm->tm_year += 1900;
#endif
*is2digits = TRUE;
} }
} }
...@@ -3564,10 +3630,13 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou ...@@ -3564,10 +3630,13 @@ DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, dou
tm->tm_mon = 1; tm->tm_mon = 1;
tm->tm_year = atoi(str + 0); tm->tm_year = atoi(str + 0);
#if 0
if (tm->tm_year < 70) if (tm->tm_year < 70)
tm->tm_year += 2000; tm->tm_year += 2000;
else if (tm->tm_year < 100) else if (tm->tm_year < 100)
tm->tm_year += 1900; tm->tm_year += 1900;
#endif
*is2digits = TRUE;
} }
else if (strchr(str, '.') != NULL) else if (strchr(str, '.') != NULL)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment