[traffxml] Use std::chrono:utc_clock for IsoTime, improve parsing

Signed-off-by: mvglasow <michael -at- vonglasow.com>
This commit is contained in:
mvglasow
2025-06-14 18:44:05 +03:00
parent ef3de2c781
commit e3d86be324
2 changed files with 23 additions and 25 deletions

View File

@@ -79,19 +79,17 @@ const std::map<EventType, uint16_t> kEventDelayMap{
std::optional<IsoTime> IsoTime::ParseIsoTime(std::string timeString) std::optional<IsoTime> IsoTime::ParseIsoTime(std::string timeString)
{ {
/* /*
* TODO this is ugly because we need to work around some compiler deficiencies. * We cannot use `std::chrono::from_stream` because it requires GCC 14+, and as of mid-2025, the
* supported development platform (Ubuntu 24.04) has GCC 13.2. Clang still does not support it.
* *
* Ideally, we would be using `std::chrono::time_point<std::chrono::utc_clock>` and parse the * As a reasonably portable workaround, we first parse the time string into its constituent values
* string using `std::chrono::from_stream`, using `%FT%T%z` for the format string. * using a regex, then build a `sys_seconds` instance from the values and use `clock_cast` to
* This works in GCC 14+ and is pleasantly liberal about the time zone format (all of +01, +0100 * convert it to a `std::chrono::time_point<std::chrono::utc_clock>` instance, which is the data
* and +01:00 are parsed correctly). Alas, Ubuntu 24.04 (currently the default dev platform) comes * type we use internally.
* with GCC 13.2, which lacks this support. Clang, as of mid-2025, doesnt support it at all.
* *
* The workaround is therefore to use `std::chrono::time_point<std::chrono::system_clock>`, which * Once we have proper support for `std::chrono::from_stream` in all toolchains we support, this
* exposes the same API as its `utc_clock` counterpart, making transition at a later point easy. * function can be rewritten accordingly. In GCC 14+, using `%FT%T%z` for the format string will
* In addition, however, it can be constructed from `std::time_t`, which we can generate from * work with all known UTC offset formats (+01, +0100 and +01:00), just like the regex does.
* `std::tm`. Still not the prettiest way (as it relies on legacy C functions which are not
* thread-safe), but the best we can get until we have proper compiler support for `from_stream`.
*/ */
/* /*
* Regex for ISO 8601 time, with some tolerance for time zone offset. If matched, the matcher * Regex for ISO 8601 time, with some tolerance for time zone offset. If matched, the matcher
@@ -121,17 +119,17 @@ std::optional<IsoTime> IsoTime::ParseIsoTime(std::string timeString)
if (offset_h < 0) if (offset_h < 0)
offset_m *= -1; offset_m *= -1;
std::tm tm = {}; const auto y = static_cast<std::chrono::year>(std::stoi(iso8601Matcher[1]));
tm.tm_year = std::stoi(iso8601Matcher[1]) - 1900; const auto mo = static_cast<std::chrono::month>(std::stoi(iso8601Matcher[2]));
tm.tm_mon = std::stoi(iso8601Matcher[2]) - 1; const auto d = static_cast<std::chrono::day>(std::stoi(iso8601Matcher[3]));
tm.tm_mday = std::stoi(iso8601Matcher[3]); const std::chrono::hours h{std::stoi(iso8601Matcher[4]) - offset_h};
tm.tm_hour = std::stoi(iso8601Matcher[4]) - offset_h; const std::chrono::minutes min{std::stoi(iso8601Matcher[5]) - offset_m};
tm.tm_min = std::stoi(iso8601Matcher[5]) - offset_m; const std::chrono::seconds s{static_cast<uint8_t>(std::stof(iso8601Matcher[6]) + 0.5f)};
tm.tm_sec = std::stof(iso8601Matcher[6]) + 0.5f;
std::time_t tt = timegm(&tm); std::chrono::sys_seconds sys_s = std::chrono::sys_days{y/mo/d};
sys_s = sys_s + h + min + s;
std::chrono::time_point<std::chrono::system_clock> tp = std::chrono::system_clock::from_time_t(tt); std::chrono::time_point<std::chrono::utc_clock> tp = std::chrono::clock_cast<std::chrono::utc_clock>(sys_s);
IsoTime result(tp); IsoTime result(tp);
return result; return result;
@@ -145,16 +143,16 @@ std::optional<IsoTime> IsoTime::ParseIsoTime(std::string timeString)
IsoTime IsoTime::Now() IsoTime IsoTime::Now()
{ {
return IsoTime(std::chrono::system_clock::now()); return IsoTime(std::chrono::utc_clock::now());
} }
IsoTime::IsoTime(std::chrono::time_point<std::chrono::system_clock> tp) IsoTime::IsoTime(std::chrono::time_point<std::chrono::utc_clock> tp)
: m_tp(tp) : m_tp(tp)
{} {}
bool IsoTime::IsPast() bool IsoTime::IsPast()
{ {
return m_tp < std::chrono::system_clock::now(); return m_tp < std::chrono::utc_clock::now();
} }
bool IsoTime::operator< (IsoTime & rhs) bool IsoTime::operator< (IsoTime & rhs)

View File

@@ -77,9 +77,9 @@ public:
private: private:
friend std::string DebugPrint(IsoTime time); friend std::string DebugPrint(IsoTime time);
IsoTime(std::chrono::time_point<std::chrono::system_clock> tp); IsoTime(std::chrono::time_point<std::chrono::utc_clock> tp);
std::chrono::time_point<std::chrono::system_clock> m_tp; std::chrono::time_point<std::chrono::utc_clock> m_tp;
}; };
// TODO enum urgency // TODO enum urgency