Allow fractional values for delta times (e.g. '2.5 days').

Check valid numeric input more carefully for delta times.
Implement day of year as possible input to datetime_part().
This commit is contained in:
Thomas G. Lockhart 1997-11-17 16:23:33 +00:00
parent 55a6b7a9be
commit e7946a53ad
1 changed files with 54 additions and 14 deletions

View 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;