Allow fractional values for delta times (e.g. '2.5 days').
authorThomas G. Lockhart
Mon, 17 Nov 1997 16:23:33 +0000 (16:23 +0000)
committerThomas G. Lockhart
Mon, 17 Nov 1997 16:23:33 +0000 (16:23 +0000)
Check valid numeric input more carefully for delta times.
Implement day of year as possible input to datetime_part().

src/backend/utils/adt/dt.c

index 070e25230fb7ea320069535276884796008612c6..b3b826fab8bcfb84478f488239f579b96b6adf95 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.43 1997/10/25 05:18:17 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.44 1997/11/17 16:23:33 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1803,6 +1803,14 @@ datetime_part(text *units, DateTime *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(WARN, "Unable to encode datetime", NULL);
+
+                   *result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
+                       - date2j(tm->tm_year, 1, 1) + 1);
+                   break;
+
                default:
                    elog(WARN, "Datetime units '%s' not supported", lowunits);
                    *result = 0;
@@ -2101,6 +2109,7 @@ static datetkn datetktbl[] = {
    {"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,         NEG(60)},       /* East Australian Std Time */
    {"edt",         DTZ,        NEG(24)},       /* Eastern Daylight Time */
@@ -2674,7 +2683,7 @@ ParseDateTime(char *timestr, char *lowstr,
        field[nf] = lp;
 
        /* leading digit? then date or time */
-       if (isdigit(*cp))
+       if (isdigit(*cp) || (*cp == '.'))
        {
            *lp++ = *cp++;
            while (isdigit(*cp))
@@ -2686,29 +2695,23 @@ ParseDateTime(char *timestr, char *lowstr,
                while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
                    *lp++ = *cp++;
 
-               /* date field? allow embedded text month */
            }
+           /* 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
-                */
            }
+           /* 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
-            */
        }
+       /* text? then date string, month, day of week, special, or timezone */
        else if (isalpha(*cp))
        {
            ftype[nf] = DTK_STRING;
@@ -3696,6 +3699,9 @@ DecodeSpecial(int field, char *lowtoken, int *val)
  * 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
+ *
  * If code is changed to read fields from first to last,
  * then use READ_FORWARD-bracketed code to allow sign
  * to persist to subsequent unsigned fields.
@@ -3709,6 +3715,7 @@ DecodeDateDelta(char *field[], int ftype[], int nf, int *dtype, struct tm * tm,
    int         is_neg = FALSE;
 #endif
 
+   char       *cp;
    int         fmask = 0,
                tmask,
                type;
@@ -3716,7 +3723,7 @@ DecodeDateDelta(char *field[], int ftype[], int nf, int *dtype, struct tm * tm,
                ii;
    int         flen,
                val;
-   char       *cp;
+   double      fval;
    double      sec;
 
    *dtype = DTK_DELTA;
@@ -3774,6 +3781,7 @@ DecodeDateDelta(char *field[], int ftype[], int nf, int *dtype, struct tm * tm,
                is_neg = (*field[i] == '-');
 #endif
 
+           case DTK_DATE:
            case DTK_NUMBER:
                val = strtol(field[i], &cp, 10);
 #if READ_FORWARD
@@ -3782,70 +3790,102 @@ DecodeDateDelta(char *field[], int ftype[], int nf, int *dtype, struct tm * tm,
 #endif
                if (*cp == '.')
                {
+                   fval = strtod(cp, &cp);
+                   if (*cp != '\0')
+                       return -1;
+
+                   if (val < 0)
+                       fval = -(fval);
+#if FALSE
                    *fsec = strtod(cp, NULL);
                    if (val < 0)
                        *fsec = -(*fsec);
+#endif
                }
+               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 * 1e-6);
+                       *fsec += ((val + fval) * 1e-6);
                        break;
 
                    case DTK_MILLISEC:
-                       *fsec += (val * 1e-3);
+                       *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;