]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
This patch fixes some problems in date handling for atypical dates.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 13 Feb 1999 05:59:34 +0000 (05:59 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 13 Feb 1999 05:59:34 +0000 (05:59 +0000)
Here is a summary:
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...
Move common macros to dt.h.

src/backend/utils/adt/datetime.c
src/backend/utils/adt/dt.c

index ac6552f4a477f71932b33b931a846688bb58df36..a8cbdadf539e1d035972189057cc786de7fbf42f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.25.2.1 1998/12/31 16:34:47 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.25.2.2 1999/02/13 05:59:34 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 static int     date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn);
 
-
+#if 0
 static int     day_tab[2][12] = {
        {31, 28, 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)
+#endif
 
 #define UTIME_MINYEAR (1901)
 #define UTIME_MINMONTH (12)
@@ -99,10 +100,12 @@ date_in(char *str)
                        elog(ERROR, "Unrecognized date external representation %s", str);
        }
 
+#if 0
        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);
        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);
+#endif
        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'",
                         day_tab[isleap(tm->tm_year)][tm->tm_mon - 1], str);
index 79f658c5947affed46e21884f05d901076bf6cc3..3eb3463089d153444797367083061bdaa7fe7e9d 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.59.2.1 1998/12/31 16:34:48 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.59.2.2 1999/02/13 05:59:34 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 #endif
 #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 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 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);
@@ -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     tm2timespan(struct tm * tm, double fsec, TimeSpan *span);
 
+
 #define USE_DATE_CACHE 1
 #define ROUND_ALL 0
 
+#if 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};
+#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",
 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
@@ -240,7 +249,7 @@ timespan_in(char *str)
                case DTK_DELTA:
                        if (tm2timespan(tm, fsec, span) != 0)
                        {
-#if FALSE
+#if NOT_USED
                                TIMESPAN_INVALID(span);
 #endif
                                elog(ERROR, "Bad timespan external representation '%s'", str);
@@ -873,6 +882,7 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
                                }
 
                                /* adjust for end of month boundary problems... */
+#if 0
                                if (tm->tm_mday > mdays[tm->tm_mon - 1])
                                {
                                        if ((tm->tm_mon == 2) && isleap(tm->tm_year))
@@ -880,6 +890,9 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
                                        else
                                                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
                                printf("datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d\n",
@@ -1184,16 +1197,22 @@ datetime_age(DateTime *datetime1, DateTime *datetime2)
                {
                        if (dt1 < dt2)
                        {
+#if 0
                                tm->tm_mday += mdays[tm1->tm_mon - 1];
                                if (isleap(tm1->tm_year) && (tm1->tm_mon == 2))
                                        tm->tm_mday++;
+#endif
+                               tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
                                tm->tm_mon--;
                        }
                        else
                        {
+#if 0
                                tm->tm_mday += mdays[tm2->tm_mon - 1];
                                if (isleap(tm2->tm_year) && (tm2->tm_mon == 2))
                                        tm->tm_mday++;
+#endif
+                               tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
                                tm->tm_mon--;
                        }
                }
@@ -1393,7 +1412,7 @@ datetime_trunc(text *units, DateTime *datetime)
 
        if (DATETIME_NOT_FINITE(*datetime))
        {
-#if FALSE
+#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
@@ -1475,7 +1494,7 @@ datetime_trunc(text *units, DateTime *datetime)
                        if (tm2datetime(tm, fsec, &tz, result) != 0)
                                elog(ERROR, "Unable to truncate datetime to '%s'", lowunits);
 
-#if FALSE
+#if NOT_USED
                }
                else if ((type == RESERV) && (val == DTK_EPOCH))
                {
@@ -1533,7 +1552,7 @@ timespan_trunc(text *units, TimeSpan *timespan)
 
        if (TIMESPAN_IS_INVALID(*timespan))
        {
-#if FALSE
+#if NOT_USED
                elog(ERROR, "Timespan is not finite", NULL);
 #endif
                result = NULL;
@@ -1591,7 +1610,7 @@ timespan_trunc(text *units, TimeSpan *timespan)
                        result = NULL;
                }
 
-#if FALSE
+#if NOT_USED
        }
        else if ((type == RESERV) && (val == DTK_EPOCH))
        {
@@ -1659,7 +1678,7 @@ datetime_part(text *units, DateTime *datetime)
 
        if (DATETIME_NOT_FINITE(*datetime))
        {
-#if FALSE
+#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
@@ -1824,7 +1843,7 @@ timespan_part(text *units, TimeSpan *timespan)
 
        if (TIMESPAN_IS_INVALID(*timespan))
        {
-#if FALSE
+#if NOT_USED
                elog(ERROR, "Timespan is not finite", NULL);
 #endif
                *result = 0;
@@ -1874,15 +1893,15 @@ timespan_part(text *units, TimeSpan *timespan)
                                        break;
 
                                case DTK_DECADE:
-                                       *result = (tm->tm_year / 10) + 1;
+                                       *result = (tm->tm_year / 10);
                                        break;
 
                                case DTK_CENTURY:
-                                       *result = (tm->tm_year / 100) + 1;
+                                       *result = (tm->tm_year / 100);
                                        break;
 
                                case DTK_MILLENIUM:
-                                       *result = (tm->tm_year / 1000) + 1;
+                                       *result = (tm->tm_year / 1000);
                                        break;
 
                                default:
@@ -2036,7 +2055,7 @@ static datetkn datetktbl[] = {
        {"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 */
+       {"ahst", TZ, NEG(60)},          /* Alaska-Hawaii Std Time */
        {"allballs", RESERV, DTK_ZULU},         /* 00:00:00 */
        {"am", AMPM, AM},
        {"apr", MONTH, 4},
@@ -2087,12 +2106,12 @@ static datetkn datetktbl[] = {
        {"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,,    est */
+       {"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 */
+       {INVALID, RESERV, DTK_INVALID},
+                                                               /* "invalid" reserved for invalid time */
        {"ist", TZ, 12},                        /* Israel */
-       {"it", TZ, 22},                         /* Iran Time */
+       {"it", TZ, 21},                         /* Iran Time */
        {"jan", MONTH, 1},
        {"january", MONTH, 1},
        {"jst", TZ, 54},                        /* Japan Std Time,USSR Zone 8 */
@@ -2283,6 +2302,8 @@ datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
  * 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
  *     to avoid having to check year and day both. - tgl 97/05/08
  */
@@ -2294,6 +2315,7 @@ datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
 #define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
  || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
   || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
+#endif
 
 int
 date2j(int y, int m, int d)
@@ -2432,7 +2454,7 @@ datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
                        tm->tm_mday = tx->tm_mday;
                        tm->tm_hour = tx->tm_hour;
                        tm->tm_min = tx->tm_min;
-#if FALSE
+#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
@@ -2792,6 +2814,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
        int                     flen,
                                val;
        int                     mer = HR24;
+       int                     haveTextMonth = FALSE;
+       int                     is2digits = FALSE;
        int                     bc = FALSE;
 
        *dtype = DTK_DATE;
@@ -2839,15 +2863,18 @@ 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)
+                                       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) != 0)
+                                       if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec, &is2digits) != 0)
                                                return -1;
                                }
                                break;
@@ -2929,14 +2956,23 @@ DecodeDateTime(char **field, int *ftype, int nf,
 #ifdef DATEDEBUG
                                                printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
 #endif
+                                               /* 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);
+#ifdef DATEDEBUG
+                                                       printf("DecodeNumber- misidentified month previously; assign as day %d\n", tm->tm_mday);
+#endif
+                                               }
+                                               haveTextMonth = TRUE;
                                                tm->tm_mon = val;
                                                break;
 
-                                               /*
-                                                * daylight savings time modifier (solves "MET
-                                                * DST" syntax)
-                                                */
                                        case DTZMOD:
+                                               /* daylight savings time modifier (solves "MET DST" syntax) */
                                                tmask |= DTK_M(DTZ);
                                                tm->tm_isdst = 1;
                                                if (tzp == NULL)
@@ -3000,7 +3036,19 @@ 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);
+       }
+       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;
@@ -3075,6 +3123,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
        int                     i;
        int                     flen,
                                val;
+       int                     is2digits = FALSE;
        int                     mer = HR24;
 
        *dtype = DTK_TIME;
@@ -3102,7 +3151,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, dou
                        case DTK_NUMBER:
                                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;
                                break;
 
@@ -3201,6 +3250,8 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
        int                     nf = 0;
        int                     i,
                                len;
+       int                     bc = FALSE;
+       int                     is2digits = FALSE;
        int                     type,
                                val,
                                dmask = 0;
@@ -3230,9 +3281,11 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
                nf++;
        }
 
+#if 0
        /* don't allow too many fields */
        if (nf > 3)
                return -1;
+#endif
 
        *tmask = 0;
 
@@ -3255,6 +3308,10 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
                                        tm->tm_mon = val;
                                        break;
 
+                               case ADBC:
+                                       bc = (val == BC);
+                                       break;
+
                                default:
 #ifdef DATEDEBUG
                                        printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
@@ -3281,7 +3338,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
                if ((len = strlen(field[i])) <= 0)
                        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;
 
                if (fmask & dmask)
@@ -3291,6 +3348,25 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
                *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() */
 
@@ -3354,7 +3430,8 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
  * 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)
+DecodeNumber(int flen, char *str, int fmask,
+                        int *tmask, struct tm * tm, double *fsec, int *is2digits)
 {
        int                     val;
        char       *cp;
@@ -3375,8 +3452,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);
@@ -3384,33 +3476,20 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
                *tmask = DTK_M(YEAR);
 
                /* already have a year? then see if we can substitute... */
-               if (fmask & DTK_M(YEAR))
+               if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
+                 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
                {
-                       if ((!(fmask & DTK_M(DAY)))
-                               && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
-                       {
+                       tm->tm_mday = tm->tm_year;
+                       *tmask = DTK_M(DAY);
 #ifdef DATEDEBUG
-                               printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
+                       printf("DecodeNumber- misidentified year previously; assign as day %d\n", tm->tm_mday);
 #endif
-                               tm->tm_mday = tm->tm_year;
-                               *tmask = DTK_M(DAY);
-                       }
                }
 
                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 +3539,18 @@ 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 0
+               if (flen == 2)
+               {
+                       if (tm->tm_year < 70)
+                               tm->tm_year += 2000;
+                       else if (tm->tm_year < 100)
+                               tm->tm_year += 1900;
+               }
+#endif
+               *is2digits = (flen == 2);
 
        }
        else
@@ -3477,7 +3564,8 @@ DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double
  * Interpret numeric string as a concatenated date field.
  */
 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;
 
@@ -3527,9 +3615,36 @@ 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 0
+                       if (tm->tm_year < 70)
+                               tm->tm_year += 2000;
+                       else if (tm->tm_year < 100)
+                               tm->tm_year += 1900;
+#endif
+                       *is2digits = TRUE;
                }
 
        }
+       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 0
+               if (tm->tm_year < 70)
+                       tm->tm_year += 2000;
+               else if (tm->tm_year < 100)
+                       tm->tm_year += 1900;
+#endif
+               *is2digits = TRUE;
+       }
        else if (strchr(str, '.') != NULL)
        {
 #ifdef DATEDEBUG