diff --git a/NEWS b/NEWS index 67f5807b4..8a8c7f905 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.21.17 (not yet released) +* protocol + - relax the ISO 8601 parser: allow omitting the time of day * archive - zzip: improve error reporting * outputs diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index a7435630a..4811813fb 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -70,14 +70,32 @@ ParseISO8601(const char *s) throw std::runtime_error("Time parsing not implemented on Windows"); #else struct tm tm{}; - const char *end = strptime(s, "%FT%TZ", &tm); - if (end == nullptr || *end != 0) - throw std::runtime_error("Failed to parse time stamp"); - std::chrono::system_clock::duration precision = std::chrono::seconds(1); + /* parse the date */ + const char *end = strptime(s, "%F", &tm); + if (end == nullptr) + throw std::runtime_error("Failed to parse date"); + + s = end; + + std::chrono::system_clock::duration precision = std::chrono::hours(24); + + /* parse the time of day */ + if (*s == 'T') { + ++s; + end = strptime(s, "%TZ", &tm); + if (end == nullptr) + throw std::runtime_error("Failed to parse time of day"); + + s = end; + precision = std::chrono::seconds(1); + } auto tp = TimeGm(tm); + if (*s != 0) + throw std::runtime_error("Garbage at end of time stamp"); + return std::make_pair(tp, precision); #endif /* !_WIN32 */ } diff --git a/test/TestISO8601.cxx b/test/TestISO8601.cxx index 59849a0b8..d5e8dd2dc 100644 --- a/test/TestISO8601.cxx +++ b/test/TestISO8601.cxx @@ -45,6 +45,12 @@ static constexpr struct { { "2019-02-04T16:46:41Z", 1549298801, std::chrono::seconds(1) }, { "2018-12-31T23:59:59Z", 1546300799, std::chrono::seconds(1) }, { "2019-01-01T00:00:00Z", 1546300800, std::chrono::seconds(1) }, + + /* only date */ + { "1970-01-01", 0, std::chrono::hours(24) }, + { "2019-02-04", 1549238400, std::chrono::hours(24) }, + { "2018-12-31", 1546214400, std::chrono::hours(24) }, + { "2019-01-01", 1546300800, std::chrono::hours(24) }, }; TEST(ISO8601, Parse)