diff tests/test-parse-datetime.c @ 15542:9ad43fa113ac

parse-datetime: accept ISO 8601 date and time rep with "T" separator The parser now accepts ISO 8601 date-time strings with "T" as the separator. It has long parsed dates like "2004-02-29 16:21:42" with a space between the date and time strings. Now it also parses "2004-02-29T16:21:42" and fractional-second and time-zone-annotated variants like "2004-02-29T16:21:42.333-07:00" * lib/parse-datetime.y: Parse ISO 8601 extended date and time of day representation using the 'T' separator character. * doc/parse-datetime.texi (General date syntax): replace use of deprecated --iso-8601 option with --rfc-3339 in example of date command output formats that can be parsed. * tests/test-parse-datetime.c (tm_diff): New function, taken from lib/parse-datetime.y. (gmt_offset): New function. (main): Add additional test cases to validate ISO8601 extended date and time of day format parsing.
author J.T. Conklin <jtc@acorntoolworks.com>
date Wed, 17 Aug 2011 16:40:49 -0700 (2011-08-17)
parents 97fc9a21a8fb
children 8e204a155dab
line wrap: on
line diff
--- a/tests/test-parse-datetime.c
+++ b/tests/test-parse-datetime.c
@@ -48,17 +48,171 @@
   NULL
 };
 
+
+#if ! HAVE_TM_GMTOFF
+/* Shift A right by B bits portably, by dividing A by 2**B and
+   truncating towards minus infinity.  A and B should be free of side
+   effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
+   INT_BITS is the number of useful bits in an int.  GNU code can
+   assume that INT_BITS is at least 32.
+
+   ISO C99 says that A >> B is implementation-defined if A < 0.  Some
+   implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
+   right in the usual way when A < 0, so SHR falls back on division if
+   ordinary A >> B doesn't seem to be the usual signed shift.  */
+#define SHR(a, b)       \
+  (-1 >> 1 == -1        \
+   ? (a) >> (b)         \
+   : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
+
+#define TM_YEAR_BASE 1900
+
+/* Yield the difference between *A and *B,
+   measured in seconds, ignoring leap seconds.
+   The body of this function is taken directly from the GNU C Library;
+   see src/strftime.c.  */
+static long int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+  /* Compute intervening leap days correctly even if year is negative.
+     Take care to avoid int overflow in leap day calculations.  */
+  int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
+  int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
+  int a100 = a4 / 25 - (a4 % 25 < 0);
+  int b100 = b4 / 25 - (b4 % 25 < 0);
+  int a400 = SHR (a100, 2);
+  int b400 = SHR (b100, 2);
+  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+  long int ayear = a->tm_year;
+  long int years = ayear - b->tm_year;
+  long int days = (365 * years + intervening_leap_days
+                   + (a->tm_yday - b->tm_yday));
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+                + (a->tm_min - b->tm_min))
+          + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+long
+gmt_offset()
+{
+  time_t now;
+  long gmtoff;
+
+  time(&now);
+
+#if !HAVE_TM_GMTOFF
+  struct tm tm_local = *localtime(&now);
+  struct tm tm_gmt   = *gmtime(&now);
+
+  gmtoff = tm_diff(&tm_local, &tm_gmt);
+#else
+  gmtoff = localtime(&now)->tm_gmtoff;
+#endif
+
+  return gmtoff;
+}
+
 int
 main (int argc _GL_UNUSED, char **argv)
 {
   struct timespec result;
   struct timespec result2;
+  struct timespec expected;
   struct timespec now;
   const char *p;
   int i;
+  long gmtoff;
 
   set_program_name (argv[0]);
 
+  gmtoff = gmt_offset();
+
+
+  /* ISO 8601 extended date and time of day representation,
+     'T' separator, local time zone */
+  p = "2011-05-01T11:55:18";
+  expected.tv_sec = 1304250918 - gmtoff;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+  /* ISO 8601 extended date and time of day representation,
+     ' ' separator, local time zone */
+  p = "2011-05-01 11:55:18";
+  expected.tv_sec = 1304250918 - gmtoff;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+
+  /* ISO 8601, extended date and time of day representation,
+     'T' separator, UTC */
+  p = "2011-05-01T11:55:18Z";
+  expected.tv_sec = 1304250918;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+  /* ISO 8601, extended date and time of day representation,
+     ' ' separator, UTC */
+  p = "2011-05-01 11:55:18Z";
+  expected.tv_sec = 1304250918;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+
+  /* ISO 8601 extended date and time of day representation,
+     'T' separator, w/UTC offset */
+  p = "2011-05-01T11:55:18-07:00";
+  expected.tv_sec = 1304276118;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+  /* ISO 8601 extended date and time of day representation,
+     ' ' separator, w/UTC offset */
+  p = "2011-05-01 11:55:18-07:00";
+  expected.tv_sec = 1304276118;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+
+  /* ISO 8601 extended date and time of day representation,
+     'T' separator, w/hour only UTC offset */
+  p = "2011-05-01T11:55:18-07";
+  expected.tv_sec = 1304276118;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+  /* ISO 8601 extended date and time of day representation,
+     ' ' separator, w/hour only UTC offset */
+  p = "2011-05-01 11:55:18-07";
+  expected.tv_sec = 1304276118;
+  expected.tv_nsec = 0;
+  ASSERT (parse_datetime (&result, p, 0));
+  LOG (p, expected, result);
+  ASSERT (expected.tv_sec == result.tv_sec
+          && expected.tv_nsec == result.tv_nsec);
+
+
   now.tv_sec = 4711;
   now.tv_nsec = 1267;
   p = "now";