From 4bc578eb838754b14b62699929a0ab30377bf71a Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Thu, 3 Apr 1997 19:58:11 +0000 Subject: [PATCH] From: "D'Arcy J.M. Cain" Subject: [HACKERS] timestamp.c changes I sent in changes previously and they were rejected because they didn't follow ANSI spec. Here is the input part of the changes again. Even though it allows more flexibility for inputting different formats, it is also backwards compatible with the standard version. I have also not changed the output format so it will still output the ANSI forms. Is this acceptable to everyone? --- src/backend/utils/adt/timestamp.c | 96 ++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 99c7d0f70f..d4fb075964 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1,27 +1,107 @@ #include #include #include +#include #include "postgres.h" #include "utils/builtins.h" +/* copy the next part of the string into a buffer */ +static const char * +cpstr(const char *s, char *buf) +{ + char in = 0; + + while (isspace(*s)) + s++; + + for (; *s && !isspace(*s); s++) + { + if (strchr("-,:/", *s)) + { + buf[in] = 0; + return(s + 1); + } + + if (in < 16) + buf[in++] = tolower(*s); + } + + buf[in] = 0; + return s; +} + +/* assumes dd/mm/yyyy unless first item is month in word form */ time_t timestamp_in(const char *timestamp_str) { struct tm input_time; int4 result; + char buf[18]; + const char *p; + static const char *mstr[] = { + "january", "february", "march", "april", "may", "june", + "july", "august", "september", "october", "november", "december" + }; memset(&input_time, 0, sizeof(input_time)); - if(sscanf(timestamp_str, "%d%*c%d%*c%d%*c%d%*c%d%*c%d", - &input_time.tm_year, &input_time.tm_mon, &input_time.tm_mday, - &input_time.tm_hour, &input_time.tm_min, &input_time.tm_sec) != 6) { - elog(WARN, "timestamp_in: timestamp \"%s\" not of the form yyyy-mm-dd hh:mm:ss", + p = cpstr(timestamp_str, buf); + if (isdigit(buf[0])) /* must be dd/mm/yyyy */ + { + input_time.tm_mday = atoi(buf); + p = cpstr(p, buf); + if (!buf[0]) + elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date", + timestamp_str); + if (isdigit(buf[0])) + { + input_time.tm_mon = atoi(buf) - 1; + if (input_time.tm_mon < 0 || input_time.tm_mon > 11) + elog(WARN, "timestamp_in: timestamp \"%s\" invalid month", + timestamp_str); + } + else + { + int i; + for (i = 0; i < 12; i++) + if (strncmp(mstr[i], buf, strlen(buf)) == 0) + break; + if (1 > 11) + elog(WARN, "timestamp_in: timestamp \"%s\" invalid month", + timestamp_str); + input_time.tm_mon = i; + } + } + else /* must be month/dd/yyyy */ + { + int i; + for (i = 0; i < 12; i++) + if (strncmp(mstr[i], buf, strlen(buf)) == 0) + break; + if (1 > 11) + elog(WARN, "timestamp_in: timestamp \"%s\" invalid month", + timestamp_str); + input_time.tm_mon = i; + p = cpstr(p, buf); + input_time.tm_mday = atoi(buf); + if (!input_time.tm_mday || input_time.tm_mday > 31) + elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date", timestamp_str); } - /* range checking? bahahahaha.... */ + p = cpstr(p, buf); + if (!buf[0] || !isdigit(buf[0])) + elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date", + timestamp_str); + if ((input_time.tm_year = atoi(buf)) < 1900) + input_time.tm_year += 1900; - input_time.tm_year -= 1900; - input_time.tm_mon -= 1; + /* now get the time */ + p = cpstr(p, buf); + input_time.tm_hour = atoi(buf); + p = cpstr(p, buf); + input_time.tm_min = atoi(buf); + p = cpstr(p, buf); + input_time.tm_sec = atoi(buf); /* use mktime(), but make this GMT, not local time */ result = mktime(&input_time); @@ -35,7 +115,7 @@ timestamp_out(time_t timestamp) char *result; struct tm *time; - time = localtime((time_t *)×tamp); + time = localtime(×tamp); result = palloc(20); sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d", time->tm_year+1900, time->tm_mon+1, time->tm_mday,