diff options
Diffstat (limited to 'src/datetime.c')
-rw-r--r-- | src/datetime.c | 130 |
1 files changed, 63 insertions, 67 deletions
diff --git a/src/datetime.c b/src/datetime.c index f7cdb89..72f0219 100644 --- a/src/datetime.c +++ b/src/datetime.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 P. J. McDermott + * Copyright (C) 2021, 2022 P. J. McDermott * * This file is part of @ * @@ -18,6 +18,9 @@ */ #define _XOPEN_SOURCE +/* glibc requires these for timegm(): */ +#define _DEFAULT_SOURCE +#define _BSD_SOURCE #include <ctype.h> #include <errno.h> @@ -29,18 +32,7 @@ #include <time.h> #include "datetime.h" #include "formats.h" - -static struct tm DATETIME_EPOCH_ = { - .tm_sec = 0, - .tm_min = 0, - .tm_hour = 0, - .tm_mday = 1, - .tm_mon = 0, - .tm_year = 70, - .tm_wday = 4, - .tm_yday = 0, - .tm_isdst = -1, -}; +#include "i18n.h" static void _datetime_buf_cpy_p(char *dst, const char *src) @@ -83,7 +75,13 @@ _datetime_reset_tm(struct tm *tm) static void _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) { - int wday; + int days_in_mon[12] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + + if (now_tm->tm_year % 4 == 0 && (now_tm->tm_year % 100 != 0 || + now_tm->tm_year % 400 == 0)) { + days_in_mon[1] = 29; + } if (arg_tm->tm_sec == INT_MIN) { arg_tm->tm_sec = 0; @@ -95,36 +93,44 @@ _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) arg_tm->tm_mday = now_tm->tm_mday; arg_tm->tm_wday = now_tm->tm_wday; *arg_sec = mktime(arg_tm); - if (*arg_sec <= mktime(now_tm)) { + if (difftime(*arg_sec, mktime(now_tm)) <= 0) { /* Specified time already happened today; use tomorrow. - * Adding the number of seconds in a day is a shortcut - * that ignores leap seconds. One better method would - * be to increment tm_mday % days in tm_mon, etc. */ - *arg_sec += 60 * 60 * 24; - now_tm = localtime(arg_sec); - arg_tm->tm_year = now_tm->tm_year; - arg_tm->tm_mon = now_tm->tm_mon; - arg_tm->tm_mday = now_tm->tm_mday; + */ + ++arg_tm->tm_mday; + arg_tm->tm_wday = (arg_tm->tm_wday + 1) % 7; + if (arg_tm->tm_mday > days_in_mon[arg_tm->tm_mon]) { + arg_tm->tm_mday = 1; + ++arg_tm->tm_mon; + if (arg_tm->tm_mon >= 12) { + arg_tm->tm_mon = 0; + ++arg_tm->tm_year; + } + } *arg_sec = mktime(arg_tm); } } else if (arg_tm->tm_mday == INT_MIN) { - /* Only a weekday specified; try tomorrow or next week. Uses - * same shortcut as above. */ - wday = arg_tm->tm_wday; + /* Only a weekday specified; try tomorrow or next week. */ arg_tm->tm_year = now_tm->tm_year; arg_tm->tm_mon = now_tm->tm_mon; arg_tm->tm_mday = now_tm->tm_mday; - arg_tm->tm_wday = now_tm->tm_wday; - if (wday <= now_tm->tm_wday) { - wday += 7; + if (arg_tm->tm_wday <= now_tm->tm_wday) { + arg_tm->tm_mday += 7; + } + arg_tm->tm_mday += arg_tm->tm_wday - now_tm->tm_wday; + if (arg_tm->tm_mday > days_in_mon[arg_tm->tm_mon]) { + arg_tm->tm_mday -= days_in_mon[arg_tm->tm_mon]; + ++arg_tm->tm_mon; + if (arg_tm->tm_mon >= 12) { + arg_tm->tm_mon = 0; + ++arg_tm->tm_year; + } } *arg_sec = mktime(arg_tm); - *arg_sec += (60 * 60 * 24) * (wday - now_tm->tm_wday); } else if (arg_tm->tm_year == INT_MIN) { /* No year specified; try this year. */ arg_tm->tm_year = now_tm->tm_year; *arg_sec = mktime(arg_tm); - if (*arg_sec <= mktime(now_tm)) { + if (difftime(*arg_sec, mktime(now_tm)) <= 0) { /* Specified time already happened this year; use next * year. */ ++arg_tm->tm_year; @@ -136,7 +142,8 @@ _datetime_normalize(struct tm *now_tm, struct tm *arg_tm, time_t *arg_sec) } int -datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) +datetime_parse(struct tm *now_tm, const char *input, + struct tm *arg_tm, time_t *arg_sec) { int date_fmt_len; int time_fmt_len; @@ -146,7 +153,6 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) size_t d; size_t t; char *end; - struct tm arg_tm; time_t sec; bool got; @@ -159,20 +165,20 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } fmt_buf = calloc(fmt_len + 1, sizeof(*fmt_buf)); if (fmt_buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } sec = *arg_sec; /* GCC is dumb. */ got = false; - for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]) ; ++t) { + for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]); ++t) { _datetime_buf_cpy_p(fmt_buf, FORMATS_TIME[t]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -189,11 +195,11 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) ++t) { _datetime_buf_cpy_p(fmt_buf + date_fmt_len, FORMATS_TIME[t]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -211,11 +217,11 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } _datetime_buf_cpy_p(fmt_buf + time_fmt_len, FORMATS_DATE[d]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -224,13 +230,13 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) } } } - for (d = 0; d < sizeof(FORMATS_MISC) / sizeof(FORMATS_MISC[0]) ; ++d) { + for (d = 0; d < sizeof(FORMATS_MISC) / sizeof(FORMATS_MISC[0]); ++d) { _datetime_buf_cpy_p(fmt_buf, FORMATS_MISC[d]); - _datetime_reset_tm(&arg_tm); - end = strptime(input, fmt_buf, &arg_tm); + _datetime_reset_tm(arg_tm); + end = strptime(input, fmt_buf, arg_tm); if (end != NULL && *end == '\0') { - _datetime_normalize(now_tm, &arg_tm, arg_sec); - if (datetime_diff_epoch(*arg_sec) >= 0) { + _datetime_normalize(now_tm, arg_tm, arg_sec); + if (arg_tm->tm_year >= 0) { free(fmt_buf); return 0; } @@ -244,7 +250,7 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec) free(fmt_buf); return 0; } else { - fputs("Unknown date format\n", stderr); + fputs(_("Unknown date format\n"), stderr); free(fmt_buf); return -1; } @@ -289,13 +295,13 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, *buf_sz = strlen(fmts[0]) + 1; *buf = calloc(*buf_sz, sizeof(**buf)); if (*buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } *out = calloc(*buf_sz, sizeof(**out)); if (*out == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -315,7 +321,7 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, ++*buf_sz; *buf = realloc(*buf, *buf_sz * sizeof(**buf)); if (*buf == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -324,7 +330,7 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out, if (resized > 0) { *out = realloc(*out, *buf_sz * sizeof(**out)); if (*out == NULL) { - fprintf(stderr, "Failed to allocate buffer: %s\n", + fprintf(stderr, _("Failed to allocate buffer: %s\n"), strerror(errno)); return -1; } @@ -386,13 +392,3 @@ datetime_strftime_misc(const struct tm *tm, char **out, size_t *buf_sz, return _datetime_strftime(FORMATS_MISC, tm, out, buf_sz, buf, i); } - -double -datetime_diff_epoch(time_t t) -{ - time_t epoch; - - epoch = timegm(&DATETIME_EPOCH_); - - return difftime(t, epoch); -} |