diff options
author | Max Kellermann <max@musicpd.org> | 2019-12-24 16:17:10 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2019-12-24 16:31:06 +0100 |
commit | 803a48e96d5c84f5bff382492da2c943f536d7bd (patch) | |
tree | 8dbf3ab08fad835c9c788085e88f051c757d77c4 /src/time | |
parent | 57b8e7f651494122e9a2fc30a1281f9d927e5b87 (diff) | |
parent | bf41d1ad2bed5cb0b7b64b0cf4f87688da43d62c (diff) |
Merge tag 'v0.21.18'
release v0.21.18
Diffstat (limited to 'src/time')
-rw-r--r-- | src/time/ISO8601.cxx | 80 |
1 files changed, 65 insertions, 15 deletions
diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index 5cb4c486c..725215ea6 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -58,6 +58,8 @@ FormatISO8601(std::chrono::system_clock::time_point tp) return FormatISO8601(GmTime(tp)); } +#ifndef _WIN32 + static std::pair<unsigned, unsigned> ParseTimeZoneOffsetRaw(const char *&s) { @@ -108,6 +110,67 @@ ParseTimeZoneOffset(const char *&s) return d; } +static const char * +ParseTimeOfDay(const char *s, struct tm &tm, + std::chrono::system_clock::duration &precision) noexcept +{ + /* this function always checks "end==s" to work around a + strptime() bug on OS X: if nothing could be parsed, + strptime() returns the input string (indicating success) + instead of nullptr (indicating error) */ + + const char *end = strptime(s, "%H", &tm); + if (end == nullptr || end == s) + return end; + + s = end; + precision = std::chrono::hours(1); + + if (*s == ':') { + /* with field separators: now a minute must follow */ + + ++s; + + end = strptime(s, "%M", &tm); + if (end == nullptr || end == s) + return nullptr; + + s = end; + precision = std::chrono::minutes(1); + + /* the "seconds" field is optional */ + if (*s != ':') + return s; + + ++s; + + end = strptime(s, "%S", &tm); + if (end == nullptr || end == s) + return nullptr; + + precision = std::chrono::seconds(1); + return end; + } + + /* without field separators */ + + end = strptime(s, "%M", &tm); + if (end == nullptr || end == s) + return s; + + s = end; + precision = std::chrono::minutes(1); + + end = strptime(s, "%S", &tm); + if (end == nullptr || end == s) + return s; + + precision = std::chrono::seconds(1); + return end; +} + +#endif + std::pair<std::chrono::system_clock::time_point, std::chrono::system_clock::duration> ParseISO8601(const char *s) @@ -138,22 +201,9 @@ ParseISO8601(const char *s) if (*s == 'T') { ++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) - precision = std::chrono::hours(1); - else + s = ParseTimeOfDay(s, tm, precision); + if (s == nullptr) throw std::runtime_error("Failed to parse time of day"); - - s = end; } auto tp = TimeGm(tm); |