From babcb4bcf4c5c37e545f174db9ba99c62ebb877a Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 3 Aug 2020 16:59:29 -0700 Subject: xparsedate: support UTC offsets. Requested in https://github.com/landley/toybox/issues/130, quoting an old version of the toybox help. This is also supported by coreutils. Set $LANG to C in the date tests so that they pass with TEST_HOST=1 (they were already failing for me, presumably related to a newer glibc). --- lib/xwrap.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'lib/xwrap.c') diff --git a/lib/xwrap.c b/lib/xwrap.c index abf0d4da..886878cd 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -964,6 +964,35 @@ time_t xvali_date(struct tm *tm, char *str) error_exit("bad date %s", str); } +// Turn a timezone specified as +HH[:MM] or Z into a value for $TZ. +static int convert_tz(char *tz, char **pp) +{ + char sign, *p = *pp; + unsigned h_off, m_off, len; + + if (*p == 'Z') { + strcpy(tz, "UTC0"); + *pp = p+1; + return 1; + } + + sign = *p++; + if (sign != '+' && sign != '-') return 0; + + if (sscanf(p, "%2u%n", &h_off, &len) != 1) return 0; + p += len; + + if (*p == ':') p++; + + if (sscanf(p, "%2u%n", &m_off, &len) != 1) return 0; + p += len; + + // We have to flip the sign because POSIX UTC offsets are backwards! + sprintf(tz, "UTC%c%02d:%02d", sign == '-' ? '+' : '-', h_off, m_off); + *pp = p; + return 1; +} + // Parse date string (relative to current *t). Sets time_t and nanoseconds. void xparsedate(char *str, time_t *t, unsigned *nano, int endian) { @@ -975,7 +1004,7 @@ void xparsedate(char *str, time_t *t, unsigned *nano, int endian) char *s = str, *p, *oldtz = 0, *formats[] = {"%Y-%m-%d %T", "%Y-%m-%dT%T", "%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d", "%H:%M", "%m%d%H%M", endian ? "%m%d%H%M%y" : "%y%m%d%H%M", - endian ? "%m%d%H%M%C%y" : "%C%y%m%d%H%M"}; + endian ? "%m%d%H%M%C%y" : "%C%y%m%d%H%M"}, tz[10]; *nano = 0; @@ -998,15 +1027,6 @@ void xparsedate(char *str, time_t *t, unsigned *nano, int endian) xvali_date(0, str); } - // Trailing Z means UTC timezone, don't expect libc to know this. - // (Trimming it off here means it won't show up in error messages.) - if ((i = strlen(str)) && toupper(str[i-1])=='Z') { - str[--i] = 0; - oldtz = getenv("TZ"); - if (oldtz) oldtz = xstrdup(oldtz); - setenv("TZ", "UTC0", 1); - } - // Try each format for (i = 0; i