From bf014019579eda6e43d3a1f249065000b30980e8 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Mon, 30 Aug 2021 20:16:25 -0400 Subject: datetime: Replace large list of formats --- (limited to 'src/datetime.c') diff --git a/src/datetime.c b/src/datetime.c index 797e955..0be1a4c 100644 --- a/src/datetime.c +++ b/src/datetime.c @@ -19,46 +19,164 @@ #define _XOPEN_SOURCE +#include #include #include #include +#include #include #include "datetime.h" -static const char *DATETIME_FMTS_[] = { -#include "datetime-formats.c" +/* IMPORTANT: All of the format strings in each array must be padded with spaces + * to be of equal lengths */ +static const char *DATETIME_DATE_FMTS_[] = { + " ", /* */ + " %a ", /* Wed */ + " %Y-%m-%d ", /* 1969-12-31 */ + " %Y/%m/%d ", /* 1969/12/31 */ + " %m-%d-%Y ", /* 12-31-1969 */ + " %m-%d ", /* 12-31 */ + " %m/%d/%Y ", /* 12/31/1969 */ + " %m/%d ", /* 12/31 */ + " %d %b %Y ", /* 31 Dec 1969 */ + " %d %b ", /* 31 Dec */ + " %d-%b-%Y ", /* 31-Dec-1969 */ + " %d-%b ", /* 31-Dec */ + " %d/%b/%Y ", /* 31/Dec/1969 */ + " %d/%b ", /* 31/Dec */ + " %a %d %b %Y ", /* Wed 31 Dec 1969 */ + " %a %d %b ", /* Wed 31 Dec */ + " %a %d-%b-%Y ", /* Wed 31-Dec-1969 */ + " %a %d-%b ", /* Wed 31-Dec */ + " %a %d/%b/%Y ", /* Wed 31/Dec/1969 */ + " %a %d/%b ", /* Wed 31/Dec */ + " %a, %d %b %Y ", /* Wed, 31 Dec 1969 */ + " %a, %d %b ", /* Wed, 31 Dec */ + " %a, %d-%b-%Y ", /* Wed, 31-Dec-1969 */ + " %a, %d-%b ", /* Wed, 31-Dec */ + " %a, %d/%b/%Y ", /* Wed, 31/Dec/1969 */ + " %a, %d/%b ", /* Wed, 31/Dec */ + " %b %d, %Y ", /* Dec 31, 1969 */ + " %b %d ", /* Dec 31 */ + " %b-%d-%Y ", /* Dec-31-1969 */ + " %b-%d ", /* Dec-31 */ + " %b/%d/%Y ", /* Dec/31/1969 */ + " %b/%d ", /* Dec/31 */ + " %a %b %d, %Y ", /* Wed Dec 31, 1969 */ + " %a %b %d ", /* Wed Dec 31 */ + " %a %b-%d-%Y ", /* Wed Dec-31-1969 */ + " %a %b-%d ", /* Wed Dec-31 */ + " %a %b/%d/%Y ", /* Wed Dec/31/1969 */ + " %a %b/%d ", /* Wed Dec/31 */ + " %a, %b %d, %Y ", /* Wed, Dec 31, 1969 */ + " %a, %b %d ", /* Wed, Dec 31 */ + " %a, %b-%d-%Y ", /* Wed, Dec-31-1969 */ + " %a, %b-%d ", /* Wed, Dec-31 */ + " %a, %b/%d/%Y ", /* Wed, Dec/31/1969 */ + " %a, %b/%d ", /* Wed, Dec/31 */ NULL }; +static const char *DATETIME_TIME_FMTS_[] = { + " %I:%M:%S %p ", /* 7:00:01 PM */ + " %H:%M:%S ", /* 19:00:01 */ + " %I:%M %p ", /* 7:00 PM */ + " %H:%M ", /* 19:00 */ + " %I%M%S %p ", /* 70001 PM */ + " %H%M%S ", /* 190001 */ + " %I%M %p ", /* 700 PM */ + " %H%M ", /* 1900 */ + NULL +}; +static const char *DATETIME_MISC_FMTS_[] = { + /* ISO 8601: 1969-12-31 delimited by "T" */ + " %Y-%m-%dT%H:%M:%S ", + " %Y-%m-%dT%H:%M ", + /* ISO 8601: 19691231 delimited by "T" */ + " %Y%m%dT%H%M%S ", + " %Y%m%dT%H%M ", + /* 19691231 */ + " %Y%m%d %I%M%S %p ", + " %Y%m%d %H%M%S ", + " %Y%m%d %I%M %p ", + " %Y%m%d %H%M ", + NULL +}; + +static void +_datetime_reset_tm(struct tm *tm) +{ + tm->tm_year = INT_MIN; + tm->tm_mon = INT_MIN; + tm->tm_mday = INT_MIN; + tm->tm_wday = INT_MIN; + tm->tm_hour = INT_MIN; + tm->tm_min = INT_MIN; + tm->tm_sec = INT_MIN; + tm->tm_isdst = INT_MIN; +} int datetime_parse(const char *input, time_t *arg_sec) { - int i; + int date_fmt_len; + int time_fmt_len; + char *fmt_buf; + int d; + int t; char *end; struct tm arg_tm; time_t now_sec; struct tm *now_tm; int wday; - for (i = 0; DATETIME_FMTS_[i] != NULL; ++i) { - arg_tm.tm_year = INT_MIN; - arg_tm.tm_mon = INT_MIN; - arg_tm.tm_mday = INT_MIN; - arg_tm.tm_wday = INT_MIN; - arg_tm.tm_hour = INT_MIN; - arg_tm.tm_min = INT_MIN; - arg_tm.tm_sec = INT_MIN; - arg_tm.tm_isdst = INT_MIN; - end = strptime(input, DATETIME_FMTS_[i], &arg_tm); + date_fmt_len = strlen(DATETIME_DATE_FMTS_[0]); + time_fmt_len = strlen(DATETIME_TIME_FMTS_[0]); + fmt_buf = calloc(date_fmt_len + time_fmt_len + 1, sizeof(*fmt_buf)); + if (fmt_buf == NULL) { + fprintf(stderr, "Failed to allocate buffer: %s\n", + strerror(errno)); + return -1; + } + + for (d = 0; DATETIME_DATE_FMTS_[d] != NULL; ++d) { + memcpy(fmt_buf, DATETIME_DATE_FMTS_[d], date_fmt_len); + for (t = 0; DATETIME_TIME_FMTS_[t] != NULL; ++t) { + memcpy(fmt_buf + date_fmt_len, DATETIME_TIME_FMTS_[t], + time_fmt_len); + _datetime_reset_tm(&arg_tm); + end = strptime(input, fmt_buf, &arg_tm); + if (end != NULL && *end == '\0') { + goto found; + } + } + } + for (t = 0; DATETIME_TIME_FMTS_[t] != NULL; ++t) { + memcpy(fmt_buf, DATETIME_TIME_FMTS_[t], time_fmt_len); + for (d = 0; DATETIME_DATE_FMTS_[d] != NULL; ++d) { + memcpy(fmt_buf + time_fmt_len, DATETIME_DATE_FMTS_[d], + date_fmt_len); + _datetime_reset_tm(&arg_tm); + end = strptime(input, fmt_buf, &arg_tm); + if (end != NULL && *end == '\0') { + goto found; + } + } + } + for (d = 0; DATETIME_MISC_FMTS_[d] != NULL; ++d) { + _datetime_reset_tm(&arg_tm); + end = strptime(input, DATETIME_MISC_FMTS_[d], &arg_tm); if (end != NULL && *end == '\0') { goto found; } } + free(fmt_buf); fprintf(stderr, "Unknown date format\n"); return -1; found: + free(fmt_buf); + if (arg_tm.tm_sec == INT_MIN) { arg_tm.tm_sec = 0; } -- cgit v0.9.1