diff options
author | J.T. Conklin <jtc@acorntoolworks.com> | 2011-08-17 16:40:49 -0700 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2011-08-31 16:23:29 +0200 |
commit | c2ecbc9a8262595b27f741e41375d06213a30fb6 (patch) | |
tree | 726d561993d28cae965b681c144279e23cffc46a /tests/test-parse-datetime.c | |
parent | a5a35f0cfc24fc0b206be30aba2bf7b98d522082 (diff) | |
download | gnulib-c2ecbc9a8262595b27f741e41375d06213a30fb6.tar.gz |
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.
Diffstat (limited to 'tests/test-parse-datetime.c')
-rw-r--r-- | tests/test-parse-datetime.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/test-parse-datetime.c b/tests/test-parse-datetime.c index 45dbae6760..4cb85d5aab 100644 --- a/tests/test-parse-datetime.c +++ b/tests/test-parse-datetime.c @@ -48,17 +48,171 @@ static const char* const day_table[] = 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"; |