Package: coreutils;
Reported by: 積丹尼 Dan Jacobson <jidanni <at> jidanni.org>
Date: Mon, 25 Aug 2014 16:02:01 UTC
Severity: normal
Tags: confirmed
View this message in rfc822 format
From: Pádraig Brady <P <at> draigBrady.com> To: Jeffery Palm <palmje <at> gmail.com>, 18328 <at> debbugs.gnu.org Cc: Geoff Kuenning <geoff <at> cs.hmc.edu> Subject: bug#18328: can't say date -d '8pm -0500' though other combos work Date: Tue, 29 Jul 2025 12:22:32 +0100
On 29/07/2025 06:02, Jeffery Palm wrote: > I took a look at this bug, and believe I have a patch that will resolve it. > > $ ../src/date --debug -d '2024-01-01 8:00:00PM -0500' > date: parsed date part: (Y-M-D) 2024-01-01 > date: parsed time part: 08:00:00pm UTC-05 > date: input timezone: parsed date/time string (-05) > date: using specified time as starting value: '20:00:00' > date: starting date/time: '(Y-M-D) 2024-01-01 20:00:00 TZ=-05' > date: '(Y-M-D) 2024-01-01 20:00:00 TZ=-05' = 1704157200 epoch-seconds > date: timezone: system default > date: final: 1704157200.000000000 (epoch-seconds) > date: final: (Y-M-D) 2024-01-02 01:00:00 (UTC) > date: final: (Y-M-D) 2024-01-01 17:00:00 (UTC-08) > date: output format: ‘%a %d %b %Y %T %Z’ > Mon 01 Jan 2024 17:00:00 PST > > > And I was able to run the coreutils testsuite with no tests failing: > > ============================================================================ > Testsuite summary for GNU coreutils 9.7.174-083f8 > ============================================================================ > # TOTAL: 533 > # PASS: 476 > # SKIP: 57 > # XFAIL: 0 > # FAIL: 0 > # XPASS: 0 > # ERROR: 0 > ============================================================================ > > Are there any other tests/changes I should consider for this? > > > Below is the patch for the changes I made for this, including a new > testcase for AM/PM with timezone. > > > --- a/lib/parse-datetime.y > +++ b/lib/parse-datetime.y > @@ -592,7 +592,7 @@ debug_print_relative_time (char const *item, > parser_control const *pc) > %token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT > %token <intval> tDAY_UNIT tDAY_SHIFT > > -%token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN > +%token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN tMERIDIAN_WITH_ZONE > %token <intval> tMONTH tORDINAL tZONE > > %token <textintval> tSNUMBER tUNUMBER > @@ -698,6 +698,27 @@ time: > set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); > pc->meridian = $6; > } > + | tUNUMBER tMERIDIAN_WITH_ZONE tSNUMBER o_colon_minutes > + { > + set_hhmmss (pc, $1.value, 0, 0, 0); > + pc->meridian = $2; > + pc->zones_seen++; > + if (! time_zone_hhmm (pc, $3, $4)) YYABORT; > + } > + | tUNUMBER ':' tUNUMBER tMERIDIAN_WITH_ZONE tSNUMBER o_colon_minutes > + { > + set_hhmmss (pc, $1.value, $3.value, 0, 0); > + pc->meridian = $4; > + pc->zones_seen++; > + if (! time_zone_hhmm (pc, $5, $6)) YYABORT; > + } > + | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tMERIDIAN_WITH_ZONE > tSNUMBER o_colon_minutes > + { > + set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); > + pc->meridian = $6; > + pc->zones_seen++; > + if (! time_zone_hhmm (pc, $7, $8)) YYABORT; > + } > | iso_8601_time > ; > > @@ -1527,14 +1548,19 @@ yylex (union YYSTYPE *lvalp, parser_control *pc) > > *p = '\0'; > tp = lookup_word (pc, buff); > - if (! tp) > + if (tp) > { > - if (debugging (pc)) > - dbg_printf (_("error: unknown word '%s'\n"), buff); > - return '?'; > + lvalp->intval = tp->value; > + if (tp->type == tMERIDIAN) > + { > + char const *p = pc->input; Better to use a non shadowing name here ^ > + while (*p && c_isspace (*p)) > + p++; > + if (*p == '-' || *p == '+') > + return tMERIDIAN_WITH_ZONE; > + } > + return tp->type; > } > - lvalp->intval = tp->value; > - return tp->type; > } > > if (c != '(') > diff --git a/tests/test-parse-datetime.c b/tests/test-parse-datetime.c > index 546b383c55..9766ed7a13 100644 > --- a/tests/test-parse-datetime.c > +++ b/tests/test-parse-datetime.c > @@ -335,6 +335,15 @@ main (_GL_UNUSED int argc, char **argv) > ASSERT (result.tv_sec == result2.tv_sec > && result.tv_nsec == result2.tv_nsec); > > + /* Check that timeone works with AM/PM */ > + p = "2024-01-01 8PM -08:00"; > + expected.tv_sec = 1704168000; > + expected.tv_nsec = 0; > + ASSERT (parse_datetime (&result, p, NULL)); > + LOG (p, expected, result); > + ASSERT (expected.tv_sec == result.tv_sec > + && expected.tv_nsec == result.tv_nsec); > + > > /* TZ out of range should cause parse_datetime failure */ > now.tv_sec = SOME_TIMEPOINT + 4711; Thanks for looking at this. This changes relative handling unfortunately: $ src/date --debug -d '2024-01-01 8:00:00PM -5 days' date: parsed date part: (Y-M-D) 2024-01-01 date: parsed time part: 08:00:00pm UTC-05 date: parsed relative part: +1 day(s) ... Wed 03 Jan 2024 01:00:00 GMT $ date --debug -d '2024-01-01 8:00:00PM -5 days' date: parsed date part: (Y-M-D) 2024-01-01 date: parsed time part: 08:00:00pm date: parsed relative part: -5 day(s) ... Wed 27 Dec 2023 20:00:00 GMT Now there is an existing ambiguity here, where the AM/PM induces the relative interpretation: $ date --debug -d '2024-01-01 8:00:00PM -5 days' date: parsed date part: (Y-M-D) 2024-01-01 date: parsed time part: 08:00:00pm date: parsed relative part: -5 day(s) $ date --debug -d '2024-01-01 8:00:00 -5 days' date: parsed date part: (Y-M-D) 2024-01-01 date: parsed time part: 08:00:00 UTC-05 date: parsed relative part: +1 day(s) BTW https://bugs.gnu.org/79078 was a recent bug report along the same lines of the relative part being unexpectedly considered as a timezone offset Now I agree we're already inconsistent in this regard, but I'm sure folks are relying on the AM/PM inducing a relative interpretation. If we were trying to make all this more consistent, IMHO we should change things so that we always interpret +|-<int> <days|minutes|...> as a relative adjustment, whereas your change does the opposite for the AM/PM case. cheers, Padraig
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.