Hello, while playing a bit with date formats, I found several issues (still present in GIT head). Current date on my machine is Fri Jun 27 11:58:47 CEST 2008, used in all examples.
1) "Strange" results of signed relative time offset [EMAIL PROTECTED] ~]$ date -d "11:40 + 60 minutes" Fri Jun 27 12:41:00 CEST 2008 [EMAIL PROTECTED] ~]$ date -d "11:40 + 61 minutes" Fri Jun 27 12:40:00 CEST 2008 [EMAIL PROTECTED] ~]$ date -d "11:40 + 62 minutes" Fri Jun 27 12:39:00 CEST 2008 2) TZ shift ignored when relative time offset by days/months/years done (doesn't matter if signed or unsigned) [EMAIL PROTECTED] ~]$ date -d "11:40 UTC+0400 +24 hours" Sat Jun 28 09:40:00 CEST 2008 [EMAIL PROTECTED] ~]$ date -d "11:40 UTC+0400 +1 day" Sat Jun 28 11:40:00 CEST 2008 3) numeric TZ is not limited by usual TZ limits UTC+14 and UTC-12 (timezone used in example is UTC+5000000:00) [EMAIL PROTECTED] ~]$ date -d "11:40 +500000000" Fri Jul 2 07:33:04 CEST 1982 4) Date with dayshift could be quiet wrong [EMAIL PROTECTED] ~]$ date -d "11:40 UTC+0200 yesterday" Mon Dec 10 11:40:00 CET 2007 5) Multiplied dayshift is allowed as valid date [EMAIL PROTECTED] src]$ date -d "11:40 40 yesterday" Sun May 18 11:40:00 CEST 2008 All of those issues are fixed by the getdate.y patch (and additional three test cases for date added in the second patch). Increase of potential shift/reduce conflicts in grammar is from 20 to 36, usually caused by some splits (tDAY_UNIT split to tDAY_UNIT, tWEEK_UNIT and tDAY_SHIFT). Some code duplicities in parser were replaced by functions. Input from example #3 and #5 now considered as invalid, others handled correctly by new grammar. This grammar past coreutils tests/misc/date without troubles. If you know about any situation where this new grammar will output invalid values, please let me know and I will try to fix it. TIA. Greetings, Ondrej Vasik
From 1a6311778c0203b116259914b321196d53ccde67 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= <[EMAIL PROTECTED]> Date: Fri, 27 Jun 2008 12:31:10 +0200 Subject: [PATCH] * tests/misc/date: add tests for new fixes of date format Signed-off-by: Ondřej Vašík <[EMAIL PROTECTED]> --- tests/misc/date | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/tests/misc/date b/tests/misc/date index fb700b5..98651a3 100755 --- a/tests/misc/date +++ b/tests/misc/date @@ -118,6 +118,11 @@ my @Tests = ['rel-1day', "-d '20050101 1 day' +%F", {OUT=>"2005-01-02"}], # ...but up to coreutils-6.9, this was rejected due to the "+". ['rel-plus1', "-d '20050101 +1 day' +%F", {OUT=>"2005-01-02"}], + #...and following three were failing up to 6-12 + ['rel-plus60m', "-d '11:40 + 60 minute' +%T", {OUT=>"12:40:00"}], + ['rel-plus6d', "-d '20070101 12:40 +6 day' $fmt", {OUT=>"2007-01-07 12:40:00"}], + ['rel-plusTZ6d', "-d '20070101 12:40 UTC+4 +6 day' $fmt", {OUT=>"2007-01-07 08:40:00"}], + ['next-s', "-d '$d1 next second' '+%Y-%m-%d %T'", {OUT=>"$d0 $ts"}], ['next-m', "-d '$d1 next minute' '+%Y-%m-%d %T'", {OUT=>"$d0 $tm"}], -- 1.5.2.2
From 55d067b5172b233c63b364cad8efc171910eddee Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= <[EMAIL PROTECTED]> Date: Fri, 27 Jun 2008 12:34:08 +0200 Subject: [PATCH] * lib/getdate.y: Several fixes for date grammar, no longer replace time zone after relative day/month/year offset Signed-off-by: Ondřej Vašík <[EMAIL PROTECTED]> --- lib/getdate.y | 242 +++++++++++++++++++++++++++++++++------------------------ 1 files changed, 140 insertions(+), 102 deletions(-) diff --git a/lib/getdate.y b/lib/getdate.y index 1deec51..f0773e9 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -1,8 +1,8 @@ %{ /* Parse a string into an internal time stamp. - Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software - Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -205,7 +205,7 @@ typedef struct union YYSTYPE; static int yylex (union YYSTYPE *, parser_control *); static int yyerror (parser_control const *, char const *); -static long int time_zone_hhmm (textint, long int); +static long int time_zone_hhmm (parser_control *,textint, long int); /* Extract into *PC any date and time info from a string of digits of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY, @@ -246,6 +246,28 @@ digits_to_date_time (parser_control *pc, textint text_int) } } +static void extract_hhmmss (parser_control *pc, long int ho, long int mi, long int sec, long int nsec) +{ + pc->hour = ho; + pc->minutes = mi; + pc->seconds.tv_sec = sec; + pc->seconds.tv_nsec = nsec; +} + +/* Extract relative time multiplied by factor */ +static void +extract_relative_time (parser_control *pc, relative_time rel, int factor) +{ + pc->rel.ns += factor*rel.ns; + pc->rel.seconds += factor*rel.seconds; + pc->rel.minutes += factor*rel.minutes; + pc->rel.hour += factor*rel.hour; + pc->rel.day += factor*rel.day; + pc->rel.month += factor*rel.month; + pc->rel.year += factor*rel.year; + pc->rels_seen = true; +} + %} /* We want a reentrant parser, even if the TZ manipulation and the calls to @@ -254,8 +276,8 @@ digits_to_date_time (parser_control *pc, textint text_int) %parse-param { parser_control *pc } %lex-param { parser_control *pc } -/* This grammar has 20 shift/reduce conflicts. */ -%expect 20 +/* This grammar has 36 shift/reduce conflicts. */ +%expect 36 %union { @@ -267,8 +289,8 @@ digits_to_date_time (parser_control *pc, textint text_int) %token tAGO tDST -%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT -%token <intval> tDAY_UNIT +%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT tDAY_UNIT +%token <intval> tDAY_SHIFT tWEEK_UNIT %token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN %token <intval> tMONTH tORDINAL tZONE @@ -313,7 +335,6 @@ item: | day { pc->days_seen++; } | rel - { pc->rels_seen = true; } | number | hybrid ; @@ -321,47 +342,70 @@ item: time: tUNUMBER tMERIDIAN { - pc->hour = $1.value; - pc->minutes = 0; - pc->seconds.tv_sec = 0; - pc->seconds.tv_nsec = 0; + extract_hhmmss (pc, $1.value, 0, 0, 0); pc->meridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { - pc->hour = $1.value; - pc->minutes = $3.value; - pc->seconds.tv_sec = 0; - pc->seconds.tv_nsec = 0; + extract_hhmmss (pc, $1.value, $3.value, 0, 0); pc->meridian = $4; } | tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes { - pc->hour = $1.value; - pc->minutes = $3.value; - pc->seconds.tv_sec = 0; - pc->seconds.tv_nsec = 0; + extract_hhmmss (pc, $1.value, $3.value, 0, 0); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($4, $5); + pc->time_zone = time_zone_hhmm (pc, $4, $5); } | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid { - pc->hour = $1.value; - pc->minutes = $3.value; - pc->seconds = $5; + extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); pc->meridian = $6; } | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes { - pc->hour = $1.value; - pc->minutes = $3.value; - pc->seconds = $5; + extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($6, $7); + pc->time_zone = time_zone_hhmm (pc, $6, $7); } - ; + | tUNUMBER ':' tUNUMBER relunit_snumber + { + extract_hhmmss (pc, $1.value, $3.value, 0, 0); + pc->meridian = MER24; + extract_relative_time (pc, $4, 1); + } + | tUNUMBER ':' tUNUMBER ':' unsigned_seconds relunit_snumber + { + extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); + pc->meridian = MER24; + extract_relative_time (pc, $6, 1); + } + | tUNUMBER ':' tUNUMBER tSNUMBER + { + extract_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 + { + extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); + pc->meridian = MER24; + } + | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER + { + extract_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); + } + | tUNUMBER ':' tUNUMBER + { + extract_hhmmss (pc, $1.value, $3.value, 0, 0); + pc->meridian = MER24; + } + ; local_zone: tLOCAL_ZONE @@ -381,16 +425,12 @@ zone: { pc->time_zone = $1; } | tZONE relunit_snumber { pc->time_zone = $1; - pc->rel.ns += $2.ns; - pc->rel.seconds += $2.seconds; - pc->rel.minutes += $2.minutes; - pc->rel.hour += $2.hour; - pc->rel.day += $2.day; - pc->rel.month += $2.month; - pc->rel.year += $2.year; - pc->rels_seen = true; } + extract_relative_time (pc, $2, 1); + } | tZONE tSNUMBER o_colon_minutes - { pc->time_zone = $1 + time_zone_hhmm ($2, $3); } + { 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 @@ -495,25 +535,9 @@ date: rel: relunit tAGO - { - pc->rel.ns -= $1.ns; - pc->rel.seconds -= $1.seconds; - pc->rel.minutes -= $1.minutes; - pc->rel.hour -= $1.hour; - pc->rel.day -= $1.day; - pc->rel.month -= $1.month; - pc->rel.year -= $1.year; - } + { extract_relative_time (pc , $1, -1); } | relunit - { - pc->rel.ns += $1.ns; - pc->rel.seconds += $1.seconds; - pc->rel.minutes += $1.minutes; - pc->rel.hour += $1.hour; - pc->rel.day += $1.day; - pc->rel.month += $1.month; - pc->rel.year += $1.year; - } + { extract_relative_time (pc , $1, 1); } ; relunit: @@ -530,10 +554,18 @@ relunit: | tMONTH_UNIT { $$ = RELATIVE_TIME_0; $$.month = 1; } | tORDINAL tDAY_UNIT - { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1; } | tUNUMBER tDAY_UNIT - { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1.value; } | tDAY_UNIT + { $$ = RELATIVE_TIME_0; $$.day = 1; } + | tORDINAL tWEEK_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1 * 7 * $2; } + | tUNUMBER tWEEK_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1.value * 7 * $2; } + | tWEEK_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1 * 7; } + | tDAY_SHIFT { $$ = RELATIVE_TIME_0; $$.day = $1; } | tORDINAL tHOUR_UNIT { $$ = RELATIVE_TIME_0; $$.hour = $1; } @@ -566,7 +598,9 @@ relunit_snumber: | tSNUMBER tMONTH_UNIT { $$ = RELATIVE_TIME_0; $$.month = $1.value; } | tSNUMBER tDAY_UNIT - { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1.value; } + | tSNUMBER tWEEK_UNIT + { $$ = RELATIVE_TIME_0; $$.day = 7* $1.value * $2; } | tSNUMBER tHOUR_UNIT { $$ = RELATIVE_TIME_0; $$.hour = $1.value; } | tSNUMBER tMINUTE_UNIT @@ -600,28 +634,17 @@ hybrid: /* Hybrid all-digit and relative offset, so that we accept e.g., "YYYYMMDD +N days" as well as "YYYYMMDD N days". */ digits_to_date_time (pc, $1); - pc->rel.ns += $2.ns; - pc->rel.seconds += $2.seconds; - pc->rel.minutes += $2.minutes; - pc->rel.hour += $2.hour; - pc->rel.day += $2.day; - pc->rel.month += $2.month; - pc->rel.year += $2.year; - pc->rels_seen = true; - } + extract_relative_time (pc, $2, 1); + } ; o_colon_minutes: - /* empty */ - { $$ = -1; } - | ':' tUNUMBER + ':' tUNUMBER { $$ = $2.value; } ; o_merid: - /* empty */ - { $$ = MER24; } - | tMERIDIAN + tMERIDIAN { $$ = $1; } ; @@ -674,8 +697,8 @@ static table const time_units_table[] = { { "YEAR", tYEAR_UNIT, 1 }, { "MONTH", tMONTH_UNIT, 1 }, - { "FORTNIGHT",tDAY_UNIT, 14 }, - { "WEEK", tDAY_UNIT, 7 }, + { "FORTNIGHT",tWEEK_UNIT, 2 }, + { "WEEK", tWEEK_UNIT, 1 }, { "DAY", tDAY_UNIT, 1 }, { "HOUR", tHOUR_UNIT, 1 }, { "MINUTE", tMINUTE_UNIT, 1 }, @@ -688,10 +711,10 @@ static table const time_units_table[] = /* Assorted relative-time words. */ static table const relative_time_table[] = { - { "TOMORROW", tDAY_UNIT, 1 }, - { "YESTERDAY",tDAY_UNIT, -1 }, - { "TODAY", tDAY_UNIT, 0 }, - { "NOW", tDAY_UNIT, 0 }, + { "TOMORROW", tDAY_SHIFT, 1 }, + { "YESTERDAY",tDAY_SHIFT, -1 }, + { "TODAY", tDAY_SHIFT, 0 }, + { "NOW", tDAY_SHIFT, 0 }, { "LAST", tORDINAL, -1 }, { "THIS", tORDINAL, 0 }, { "NEXT", tORDINAL, 1 }, @@ -817,12 +840,27 @@ static table const military_table[] = to be picked apart; otherwise, S is of the form HH. */ static long int -time_zone_hhmm (textint s, long int mm) +time_zone_hhmm (parser_control *pc, textint s, long int mm) { + long int returnvalue; + + /* if s.value is lower than 15, add 00 minutes if mm not specified + as common time zones ranges between UTC-1200 and UTC+1400 */ + if ((abs (s.value) < 15) && (mm < 0)) + s.value *= 100; + if (mm < 0) - return (s.value / 100) * 60 + s.value % 100; + returnvalue = (s.value / 100) * 60 + s.value % 100; else - return s.value * 60 + (s.negative ? -mm : mm); + returnvalue = s.value * 60 + (s.negative ? -mm : mm); + + /* check if the return value is in real timezone range, + otherwise increment pc->zones_seen to cause time format + error, allow UTC-1200 to UTC+1400 */ + if ((returnvalue > 840) || (returnvalue < -720)) + pc->zones_seen++; + + return returnvalue; } static int @@ -1436,25 +1474,6 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) goto fail; } - if (pc.zones_seen) - { - long int delta = pc.time_zone * 60; - time_t t1; -#ifdef HAVE_TM_GMTOFF - delta -= tm.tm_gmtoff; -#else - time_t t = Start; - struct tm const *gmt = gmtime (&t); - if (! gmt) - goto fail; - delta -= tm_diff (&tm, gmt); -#endif - t1 = Start - delta; - if ((Start < t1) != (delta < 0)) - goto fail; /* time_t overflow */ - Start = t1; - } - /* Add relative date. */ if (pc.rel.year | pc.rel.month | pc.rel.day) { @@ -1477,6 +1496,25 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) goto fail; } + if (pc.zones_seen) + { + long int delta = pc.time_zone * 60; + time_t t1; +#ifdef HAVE_TM_GMTOFF + delta -= tm.tm_gmtoff; +#else + time_t t = Start; + struct tm const *gmt = gmtime (&t); + if (! gmt) + goto fail; + delta -= tm_diff (&tm, gmt); +#endif + t1 = Start - delta; + if ((Start < t1) != (delta < 0)) + goto fail; /* time_t overflow */ + Start = t1; + } + /* Add relative hours, minutes, and seconds. On hosts that support leap seconds, ignore the possibility of leap seconds; e.g., "+ 10 minutes" adds 600 seconds, even if one of them is a -- 1.5.2.2
signature.asc
Description: Toto je digitálně podepsaná část zprávy