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,