GNU bug report logs -
#18328
date: '8pm -0500' is invalid (am/pm problem)
Previous Next
To reply to this bug, email your comments to 18328 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-coreutils <at> gnu.org
:
bug#18328
; Package
coreutils
.
(Mon, 25 Aug 2014 16:02:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
積丹尼 Dan Jacobson <jidanni <at> jidanni.org>
:
New bug report received and forwarded. Copy sent to
bug-coreutils <at> gnu.org
.
(Mon, 25 Aug 2014 16:02:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
$ date -d '8pm -0500'
date: invalid date ‘8pm -0500’ <--why can't this combo work?
$ date -d '20:00 -0500'
二 8月 26 09:00:00 CST 2014
$ date -d 'sun 8pm'
日 8月 31 20:00:00 CST 2014
$ date -d '8pm'
一 8月 25 20:00:00 CST 2014
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18328
; Package
coreutils
.
(Sat, 20 Oct 2018 04:26:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 18328 <at> debbugs.gnu.org (full text, mbox):
tags 18328 confirmed
retitle 18328 date: '8pm -0500' is invalid (am/pm problem)
stop
(triaging old bugs)
Hello,
On 25/08/14 10:01 AM, 積丹尼 Dan Jacobson wrote:
> $ date -d '8pm -0500'
> date: invalid date ‘8pm -0500’ <--why can't this combo work?
This is indeed a bug (specifically in gnulib's date parsing module,
but easier to track here).
It seems the existence of the "am/pm" string causes the parser
to take a slightly different rule, then reject additional relative
values, unless they have a unit, e.g.:
$ date --debug -d '8pm +5 days'
date: parsed time part: 08:00:00pm
date: parsed relative part: +5 day(s)
[...]
Contrast it with a different (and confusing) rules when there is
no "am/pm", the relative number is always taken as the time zone, e.g.:
$ date --debug -d '8:00 +5 days'
date: parsed time part: 08:00:00 UTC+05
date: parsed relative part: +1 day(s)
date: input timezone: parsed date/time string (+05)
[...]
(from https://bugs.gnu.org/17161#31 )
I hope to get to this bug soon.
-assaf
Added tag(s) confirmed.
Request was from
Assaf Gordon <assafgordon <at> gmail.com>
to
control <at> debbugs.gnu.org
.
(Sat, 20 Oct 2018 04:26:02 GMT)
Full text and
rfc822 format available.
Changed bug title to 'date: '8pm -0500' is invalid (am/pm problem)' from 'can't say date -d '8pm -0500' though other combos work'
Request was from
Assaf Gordon <assafgordon <at> gmail.com>
to
control <at> debbugs.gnu.org
.
(Sat, 20 Oct 2018 04:26:02 GMT)
Full text and
rfc822 format available.
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18328
; Package
coreutils
.
(Sat, 20 Oct 2018 06:31:02 GMT)
Full text and
rfc822 format available.
Message #15 received at 18328 <at> debbugs.gnu.org (full text, mbox):
AG> I hope to get to this bug soon.
Good.
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18328
; Package
coreutils
.
(Tue, 29 Jul 2025 05:16:03 GMT)
Full text and
rfc822 format available.
Message #18 received at 18328 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
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;
+ 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;
[Message part 2 (text/html, inline)]
Information forwarded
to
bug-coreutils <at> gnu.org
:
bug#18328
; Package
coreutils
.
(Tue, 29 Jul 2025 11:23:02 GMT)
Full text and
rfc822 format available.
Message #21 received at 18328 <at> debbugs.gnu.org (full text, mbox):
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
This bug report was last modified 44 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.