From 15ce8eb48793b3d74fea041e8fe6b8fdbb328a04 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 16 Dec 2019 23:15:48 +0100 Subject: [PATCH] time/ISO8601: support omitting field separators Closes https://github.com/MusicPlayerDaemon/MPD/issues/685 --- NEWS | 4 ++-- src/time/ISO8601.cxx | 14 ++++++++++++-- test/TestISO8601.cxx | 9 +++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 986f22c87..1467ddb97 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ ver 0.21.17 (not yet released) * protocol - - relax the ISO 8601 parser: allow omitting the time of day and the "Z" - suffix + - relax the ISO 8601 parser: allow omitting field separators, the + time of day and the "Z" suffix * archive - zzip: improve error reporting * outputs diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index b92a0e743..5cb4c486c 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -123,8 +123,12 @@ ParseISO8601(const char *s) /* parse the date */ const char *end = strptime(s, "%F", &tm); - if (end == nullptr) - throw std::runtime_error("Failed to parse date"); + if (end == nullptr) { + /* try without field separators */ + end = strptime(s, "%Y%m%d", &tm); + if (end == nullptr) + throw std::runtime_error("Failed to parse date"); + } s = end; @@ -136,6 +140,12 @@ ParseISO8601(const char *s) if ((end = strptime(s, "%T", &tm)) != nullptr) precision = std::chrono::seconds(1); + else if ((end = strptime(s, "%H%M%S", &tm)) != nullptr) + /* no field separators */ + precision = std::chrono::seconds(1); + else if ((end = strptime(s, "%H%M", &tm)) != nullptr) + /* no field separators */ + precision = std::chrono::minutes(1); else if ((end = strptime(s, "%H:%M", &tm)) != nullptr) precision = std::chrono::minutes(1); else if ((end = strptime(s, "%H", &tm)) != nullptr) diff --git a/test/TestISO8601.cxx b/test/TestISO8601.cxx index 3305b47de..cd0897c1a 100644 --- a/test/TestISO8601.cxx +++ b/test/TestISO8601.cxx @@ -71,6 +71,15 @@ static constexpr struct { { "2019-02-04T16:46:41+0200", 1549291601, std::chrono::seconds(1) }, { "2019-02-04T16:46:41+02:00", 1549291601, std::chrono::seconds(1) }, { "2019-02-04T16:46:41-0200", 1549306001, std::chrono::seconds(1) }, + + /* without field separators */ + { "19700101T000000Z", 0, std::chrono::seconds(1) }, + { "19700101T000001Z", 1, std::chrono::seconds(1) }, + { "20190204T164641Z", 1549298801, std::chrono::seconds(1) }, + { "19700101", 0, std::chrono::hours(24) }, + { "20190204", 1549238400, std::chrono::hours(24) }, + { "20190204T1646", 1549298760, std::chrono::minutes(1) }, + { "20190204T16", 1549296000, std::chrono::hours(1) }, }; TEST(ISO8601, Parse)