Re: getdate.y question
Derek Robert Price <[email protected]> Thu, 28 Oct 2004 14:38:03 -0400
| Newsgroups | gmane.comp.lib.gnulib.bugs,gmane.comp.version-control.cvs.bugs |
|---|---|
| Organization | Ximbiot <http://ximbiot.com> |
| Message-ID | <[email protected]> |
Paul Eggert wrote: >"Jim.Hyslop" <[email protected]> writes: > > > >>Refactor the functionality out of mktime into a separate function, >>say mktime_checked, which accepts an additional boolean parameter, >>say allow_overflow. >> >> > >There's no need for any of this. All you have to do is check that the >output of mktime (the struct tm, that is) is the same as the input. > >The only problem comes up near the boundary conditions like 2038, >where the time zone of the time stamp may differ from your time zone. > > I finally got around to taking a shot at this. The original problem is that getdate is currently not rejecting dates like January 40th, 2004, but rather converting them. In this example it currently returns February 9th, 2004. Paul, you were right about the basic patch being pretty simple, but I have no idea if I approached the boundry conditions correctly (in fact, I haven't special-cased them - I started to but discovered that the patch was already doing what I wanted as far as I could tell). At the very least, this patch causes getdate to reject improper dates that are not near the boundries and is an improvement over what getdate.y is currently doing and I think it should definitely be applied. * lib/getdate.y (not_equal_tm): New function. (getdate): Verify that mktime() did not need to "repair" the date. The attached script will demonstrate that getdate works when it can find an executable named "getdate". If you'll note the final six tests, I failed to find a boundry condition near 1970-01-01, but it _does_ still appear to be rejecting dates as it is supposed to. The fact that I couldn't find the boundry led me to believe that there is something here that I do not understand, however. Input: 1969-12-32 2:00:00 UTC 1970-01-01 2:00:00 UTC 1969-12-32 2:00:00 +0400 1970-01-01 2:00:00 +0400 1969-12-32 2:00:00 -0400 1970-01-01 2:00:00 -0400 Output: > Bad format - couldn't convert. > 1970-01-01 02:00:00.000000000 > Bad format - couldn't convert. > 1969-12-31 22:00:00.000000000 > Bad format - couldn't convert. > 1970-01-01 06:00:00.000000000 Again, the attached patch should almost certainly be applied, but if someone could explain the boundry conditions to me more clearly and it turns out they are not being handled, I can take a shot at handling them as well, in a second patch. Feel free to add the attached test script to the GNULIB test suite too, if you like. The (separate) CVS test suite, which makes fairly heavy use of getdate, passes using the current getdate.y from GNULIB with this patch applied, meaning that at least as far as the dates in old CVS test suite are concerned, the new getdate behavior matches the old. Cheers, Derek -- *8^) Email: [email protected] Get CVS support at <http://ximbiot.com>! _______________________________________________ Bug-gnulib mailing list [email protected] http://lists.gnu.org/mailman/listinfo/bug-gnulib
13getdate-verify.diff
(text/plain, 1.8 KB)
Index: lib/getdate.y
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getdate.y,v
retrieving revision 1.85
diff -u -p -r1.85 getdate.y
--- lib/getdate.y 25 Oct 2004 05:50:16 -0000 1.85
+++ lib/getdate.y 28 Oct 2004 18:17:15 -0000
@@ -990,6 +990,29 @@ yyerror (parser_control *pc ATTRIBUTE_UN
return 0;
}
+
+
+/* Report if two struct tms are the same. Ignores tm_wday and tm_yday since
+ * mktime() can set them harmlessly as far as get_date() is concerned. This
+ * function is used to find if mktime() normalized a date, for instance
+ * converting January 40th to February 9th, which mktime() is perfectly happy
+ * to do.
+ *
+ * This was originally copied from GNULIB's lib/mktime.c and modified.
+ */
+static bool
+not_equal_tm (const struct tm *a, const struct tm *b)
+{
+ return (a->tm_sec ^ b->tm_sec)
+ | (a->tm_min ^ b->tm_min)
+ | (a->tm_hour ^ b->tm_hour)
+ | (a->tm_mday ^ b->tm_mday)
+ | (a->tm_mon ^ b->tm_mon)
+ | (a->tm_year ^ b->tm_year);
+}
+
+
+
/* Parse a date/time string, storing the resulting time value into *RESULT.
The string itself is pointed to by P. Return true if successful.
P can be an incomplete or relative time specification; if so, use
@@ -1181,6 +1204,17 @@ get_date (struct timespec *result, char
if (Start == (time_t) -1)
return false;
}
+ else if (!pc.rels_seen && not_equal_tm (&tm0, &tm))
+ {
+ /* If our time struct going in is different than the one coming out, then
+ * mktime() found cause to normalize it. This means the date was
+ * something like "January 40th, 2004", which would cause mktime to "fix"
+ * the tm, returning "February 9th, 2004".
+ *
+ * The getdate() charter says to reject these sorts of dates.
+ */
+ return false;
+ }
if (pc.days_seen && ! pc.dates_seen)
{
test-getdate.sh
(application/x-sh, 1.8 KB)
#! /bin/sh # Test that a getdate executable meets its specification. # # Copyright (C) 2004 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 # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ TZ=UTC; export TZ cat >getdate-expected <<EOF Enter date, or blank line to exit. > Bad format - couldn't convert. > Bad format - couldn't convert. > 1972-12-05 00:00:00.000000000 > 1974-03-29 00:00:00.000000000 > 1996-05-12 13:57:45.000000000 > 2012-05-12 00:00:00.000000000 > 1996-05-12 00:00:00.000000000 > Bad format - couldn't convert. > Bad format - couldn't convert. > 1970-01-01 02:00:00.000000000 > Bad format - couldn't convert. > 1969-12-31 22:00:00.000000000 > Bad format - couldn't convert. > 1970-01-01 06:00:00.000000000 > EOF ./getdate >getdate-got <<EOF February 29, 2003 2004-12-40 Dec-5-1972 3/29/1974 1996/05/12 13:57:45 12-05-12 05/12/96 third tuesday in March, 2078 1969-12-32 2:00:00 UTC 1970-01-01 2:00:00 UTC 1969-12-32 2:00:00 +0400 1970-01-01 2:00:00 +0400 1969-12-32 2:00:00 -0400 1970-01-01 2:00:00 -0400 EOF echo >>getdate-got if diff -u getdate-expected getdate-got >getdate.diff; then :; else echo "Failed! See getdate.diff for more!" >&2 exit 1 fi rm getdate-expected getdate-got getdate.diff exit 0
signature.asc
(application/pgp-signature, 252 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFBgTyNLD1OTBfyMaQRAhCrAKDfBIiX469uJIvfe4+VeSh4PjtRLwCeNu+Y VoZ7F4h/X1NJi6Q6P2xz7C8= =YOr3 -----END PGP SIGNATURE-----