summaryrefslogtreecommitdiff
path: root/src/time
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2019-12-24 16:17:10 +0100
committerMax Kellermann <max@musicpd.org>2019-12-24 16:31:06 +0100
commit803a48e96d5c84f5bff382492da2c943f536d7bd (patch)
tree8dbf3ab08fad835c9c788085e88f051c757d77c4 /src/time
parent57b8e7f651494122e9a2fc30a1281f9d927e5b87 (diff)
parentbf41d1ad2bed5cb0b7b64b0cf4f87688da43d62c (diff)
Merge tag 'v0.21.18'
release v0.21.18
Diffstat (limited to 'src/time')
-rw-r--r--src/time/ISO8601.cxx80
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);