Hello,
as reported in
https://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/51106 ,
date sometimes produces different than expected output. I know it's
impossible to cover all possible date/time formats by grammar, but the
format "HH:MM + X minutes" looks quite common for me. I improved the
grammar of getdate.y to handle this situation - with side effect that
obscure date format "HH:MM +T day ago" won't work now (+T means timezone
here, +X means relative offset number). 
Note: "HH:MM +T yesterday" or "HH:MM +T +X days" works without troubles
even in new grammar.

Greetings,
         Ondřej Vašík
From 4625a73ca2221a43c46da946ae27af3e4967cd69 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= <ova...@redhat.com>
Date: Mon, 30 Jun 2008 17:32:28 +0200
Subject: [PATCH] getdate.y: Allow usage of relative signed time offset even before time zone is specified.

* lib/getdate.y (time) : Improve grammar to allow relative signed time offset
                         even before time zone.
                (zone) : likewise
              (hybrid) : Empty strings handling no longer necessary
                         (handled directly in the changes above).
* tests/test-getdate.c (main) : Add tests for this change.
* ChangeLog : Mention changes.
---
 ChangeLog            |    6 +++++
 lib/getdate.y        |   52 +++++++++++++++++++++++++++++++++++++++++--------
 tests/test-getdate.c |   28 ++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2d9b9ab..e13525a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-23  Ondřej Vašík  <ova...@redhat.com>
+	* lib/getdate.y: Improve grammar to allow relative signed time offsets even
+	before timezone specified.
+	Reported in https://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/51106
+	* tests/test-getdate.c: Add test for this grammar improvement
+
 2009-09-23  Bruno Haible  <br...@clisp.org>
 
 	* gnulib-tool (func_import): Add 'link-warning' to testsrelated_modules
diff --git a/lib/getdate.y b/lib/getdate.y
index f022710..3f905ca 100644
--- a/lib/getdate.y
+++ b/lib/getdate.y
@@ -288,8 +288,8 @@ set_hhmmss (parser_control *pc, long int hour, long int minutes,
 %parse-param { parser_control *pc }
 %lex-param { parser_control *pc }
 
-/* This grammar has 20 shift/reduce conflicts. */
-%expect 20
+/* This grammar has 32 shift/reduce conflicts. */
+%expect 32
 
 %union
 {
@@ -381,7 +381,43 @@ time:
 	pc->zones_seen++;
 	pc->time_zone = time_zone_hhmm (pc, $6, $7);
       }
-  ;
+  | tUNUMBER ':' tUNUMBER relunit_snumber
+      {
+  set_hhmmss (pc, $1.value, $3.value, 0, 0);
+	pc->meridian = MER24;
+	apply_relative_time (pc, $4, 1);
+      }
+  | tUNUMBER ':' tUNUMBER ':' unsigned_seconds relunit_snumber
+      {
+  set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+	pc->meridian = MER24;
+	apply_relative_time (pc, $6, 1);
+      }
+  | tUNUMBER ':' tUNUMBER
+      {
+  set_hhmmss (pc, $1.value, $3.value, 0, 0);
+	pc->meridian = MER24;
+      }
+  | tUNUMBER ':' tUNUMBER tSNUMBER
+      {
+  set_hhmmss (pc, $1.value, $3.value, 0, 0);
+	pc->meridian = MER24;
+	pc->zones_seen++;
+	pc->time_zone = time_zone_hhmm (pc, $4, -1);
+      }
+  | tUNUMBER ':' tUNUMBER ':' unsigned_seconds
+      {
+  set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+	pc->meridian = MER24;
+      }
+  | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER
+      {
+  set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+	pc->meridian = MER24;
+	pc->zones_seen++;
+	pc->time_zone = time_zone_hhmm (pc, $6, -1);
+      }
+   ;
 
 local_zone:
     tLOCAL_ZONE
@@ -404,6 +440,8 @@ zone:
 	apply_relative_time (pc, $2, 1); }
   | tZONE tSNUMBER o_colon_minutes
       { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); }
+  | tZONE tSNUMBER
+      { pc->time_zone = $1 + time_zone_hhmm (pc, $2, -1); }
   | tDAYZONE
       { pc->time_zone = $1 + 60; }
   | tZONE tDST
@@ -609,16 +647,12 @@ hybrid:
   ;
 
 o_colon_minutes:
-    /* empty */
-      { $$ = -1; }
-  | ':' tUNUMBER
+  ':' tUNUMBER
       { $$ = $2.value; }
   ;
 
 o_merid:
-    /* empty */
-      { $$ = MER24; }
-  | tMERIDIAN
+  tMERIDIAN
       { $$ = $1; }
   ;
 
diff --git a/tests/test-getdate.c b/tests/test-getdate.c
index ea70527..cbc3e29 100644
--- a/tests/test-getdate.c
+++ b/tests/test-getdate.c
@@ -224,6 +224,34 @@ main (int argc, char **argv)
   ASSERT (result.tv_sec == result2.tv_sec
 	  && result.tv_nsec == result2.tv_nsec);
 
+  /* Check relative time-offsets without specified timezone */
+  now.tv_sec = 4711;
+  now.tv_nsec = 1267;
+  p = "-8 minutes";
+  ASSERT (get_date (&result, p, &now));
+  LOG (p, now, result);
+  p = "8 minutes ago";
+  ASSERT (get_date (&result2, p, &now));
+  LOG (p, now, result2);
+  ASSERT (result.tv_sec == result2.tv_sec
+	  && result.tv_nsec == result2.tv_nsec);
+  p = "+8 hours";
+  ASSERT (get_date (&result, p, &now));
+  LOG (p, now, result);
+  p = "8 hours";
+  ASSERT (get_date (&result2, p, &now));
+  LOG (p, now, result2);
+  ASSERT (result.tv_sec == result2.tv_sec
+	  && result.tv_nsec == result2.tv_nsec);
+  p = "UTC +8 hours";
+  ASSERT (get_date (&result, p, &now));
+  LOG (p, now, result);
+  p = "UTC 8 hours";
+  ASSERT (get_date (&result2, p, &now));
+  LOG (p, now, result2);
+  ASSERT (result.tv_sec == result2.tv_sec
+	  && result.tv_nsec == result2.tv_nsec);
+
   /* Check that some "next Monday", "last Wednesday", etc. are correct.  */
   putenv ("TZ=UTC0");
   for (i = 0; day_table[i]; i++)
-- 
1.5.6.1.156.ge903b

Attachment: signature.asc
Description: Toto je digitálně podepsaná část zprávy

Reply via email to