|
@@ -1,6 +1,7 @@
|
|
|
#pragma once
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cctype>
|
|
#include <cctype>
|
|
|
|
|
+#include <chrono>
|
|
|
#include <cstddef>
|
|
#include <cstddef>
|
|
|
#include <cstring>
|
|
#include <cstring>
|
|
|
#include <ctime>
|
|
#include <ctime>
|
|
@@ -50,6 +51,21 @@ inline result date(std::string_view dt) {
|
|
|
}
|
|
}
|
|
|
return {.consumed = 0L, .valid = false};
|
|
return {.consumed = 0L, .valid = false};
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+inline bool is_leapsecond(std::tm tm) {
|
|
|
|
|
+ if (tm.tm_sec != 60) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+#if __cpp_lib_chrono >= 201907L
|
|
|
|
|
+ tm.tm_isdst = -1;
|
|
|
|
|
+ std::chrono::seconds time(std::mktime(&tm));
|
|
|
|
|
+ auto const &leap_seconds = std::chrono::get_tzdb().leap_seconds;
|
|
|
|
|
+ return std::ranges::find(leap_seconds, time) != leap_seconds.end();
|
|
|
|
|
+#else
|
|
|
|
|
+ return false;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
namespace jvalidate::format {
|
|
namespace jvalidate::format {
|
|
@@ -59,7 +75,7 @@ inline bool date(std::string_view dt) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
inline bool time(std::string_view dt) {
|
|
inline bool time(std::string_view dt) {
|
|
|
- struct tm tm;
|
|
|
|
|
|
|
+ std::tm tm;
|
|
|
char const * end = strptime(dt.data(), "%T", &tm);
|
|
char const * end = strptime(dt.data(), "%T", &tm);
|
|
|
if (end == nullptr || end == dt.end() || (end - dt.data()) < 8) {
|
|
if (end == nullptr || end == dt.end() || (end - dt.data()) < 8) {
|
|
|
return false;
|
|
return false;
|
|
@@ -76,10 +92,10 @@ inline bool time(std::string_view dt) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (dt[0] == 'Z' || dt[0] == 'z') {
|
|
if (dt[0] == 'Z' || dt[0] == 'z') {
|
|
|
- return dt.size() == 1;
|
|
|
|
|
|
|
+ return dt.size() == 1 && detail::is_leapsecond(tm);
|
|
|
}
|
|
}
|
|
|
if (std::strchr("+-", dt[0])) {
|
|
if (std::strchr("+-", dt[0])) {
|
|
|
- return strptime(dt.data() + 1, "%R", &tm) == dt.end();
|
|
|
|
|
|
|
+ return strptime(dt.data() + 1, "%R", &tm) == dt.end() && detail::is_leapsecond(tm);
|
|
|
}
|
|
}
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|