diff --git a/CMakeLists.txt b/CMakeLists.txt index babc969..e3e9dfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,8 @@ set(sources set(dependencies freertos esp_timer - cpputils date - fmt ) idf_component_register( diff --git a/src/espchrono.cpp b/src/espchrono.cpp index 6d25e28..a0185c4 100644 --- a/src/espchrono.cpp +++ b/src/espchrono.cpp @@ -1,7 +1,7 @@ #include "espchrono.h" -// 3rdparty lib includes -#include +// system includes +#include using namespace std::chrono_literals; using namespace date; @@ -215,6 +215,20 @@ utc_clock::time_point fromDateTime(DateTime ts) }; } +local_clock::time_point fromDateTime(LocalDateTime ts) +{ + const sys_days date = ts.date; + return local_clock::time_point { + date.time_since_epoch() + + std::chrono::hours{ts.hour} + + std::chrono::minutes{ts.minute} + + std::chrono::seconds{ts.second} + + std::chrono::milliseconds{ts.millisecond} + + std::chrono::microseconds{ts.microsecond} + , ts.timezone, ts.dst + }; +} + std::expected parseDateTime(std::string_view str) { // both valid: @@ -234,7 +248,7 @@ std::expected parseDateTime(std::string_view str) constexpr auto dateTimeFormat = "%4d-%2u-%2uT%2hhu:%2hhu:%2hhu.%3hu.%3hu"; if (const auto scanned = std::sscanf(str.data(), dateTimeFormat, &year, &month, &day, &hour, &minute, &second, &millisecond, µsecond); scanned < 5) - return std::unexpected(fmt::format("invalid DateTime ({})", str)); + return std::unexpected(std::format("invalid DateTime ({})", str)); return DateTime{ .date=date::year_month_day{date::year{year}, date::month{month}, date::day{day}}, @@ -252,36 +266,45 @@ std::expected parseDaypoint(std::string_view constexpr auto daypointFormat = "%2hhd:%2hhd:%2hhd"; if (const auto scanned = std::sscanf(str.data(), daypointFormat, &hour, &minute, &second); scanned < 2) - return std::unexpected(fmt::format("invalid daypoint ({})", str)); + return std::unexpected(std::format("invalid daypoint ({})", str)); if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) - return std::unexpected(fmt::format("invalid daypoint ({})", str)); + return std::unexpected(std::format("invalid daypoint ({})", str)); return std::chrono::hours{hour} + std::chrono::minutes{minute} + std::chrono::seconds{second}; } std::string toString(const DateTime &dateTime) { - return fmt::format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}", - int{dateTime.date.year()}, unsigned{dateTime.date.month()}, unsigned{dateTime.date.day()}, - dateTime.hour, dateTime.minute, dateTime.second, dateTime.millisecond); + const auto tp = fromDateTime(dateTime); + auto now = toTimeT(tp); + char buf[sizeof "1970-01-01T00:00:00Z"]; + strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now)); + return buf; } std::string toString(const LocalDateTime &dateTime) { - date::hh_mm_ss helper{dateTime.timezone.offset + hours32{dateTime.dst ? 1 : 0}}; + auto tp = fromDateTime(dateTime); - return fmt::format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03} {}{:02}:{:02}", - int{dateTime.date.year()}, unsigned{dateTime.date.month()}, unsigned{dateTime.date.day()}, - dateTime.hour, dateTime.minute, dateTime.second, dateTime.millisecond, - helper.is_negative() ? "-" : "+", uint8_t(helper.hours().count()), uint8_t(helper.minutes().count())); + time_t rawtime = toTimeT(tp); + tm* timeinfo; + + timeinfo = localtime(&rawtime); + + timeinfo->tm_isdst = dateTime.dst; + timeinfo->tm_isdst += dateTime.timezone.offset.count() / 60; + + char buf[sizeof "1970-01-01T00:00:00+00:00"]; + strftime(buf, sizeof buf, "%FT%T%z", timeinfo); + return buf; } std::string toDaypointString(std::chrono::seconds seconds) { date::hh_mm_ss helper(seconds); - return fmt::format("{}{:02}:{:02}:{:02}", + return std::format("{}{:02}:{:02}:{:02}", helper.is_negative() ? "-" : "", helper.hours().count(), helper.minutes().count(), @@ -293,9 +316,18 @@ std::chrono::microseconds ago(millis_clock::time_point a) return millis_clock::now() - a; } -std::string toString(milliseconds32 val) { return fmt::format("{}ms", val.count()); } -std::string toString(seconds32 val) { return fmt::format("{}s", val.count()); } -std::string toString(minutes32 val) { return fmt::format("{}min", val.count()); } -std::string toString(hours32 val) { return fmt::format("{}h", val.count()); } +std::string toString(milliseconds32 val) { return std::format("{}ms", val.count()); } +std::string toString(seconds32 val) { return std::format("{}s", val.count()); } +std::string toString(minutes32 val) { return std::format("{}min", val.count()); } +std::string toString(hours32 val) { return std::format("{}h", val.count()); } +time_t toTimeT(utc_clock::time_point ts) +{ + return std::chrono::duration_cast(ts.time_since_epoch()).count(); +} + +time_t toTimeT(local_clock::time_point ts) +{ + return std::chrono::duration_cast(ts.time_since_epoch()).count(); +} } // namespace espchrono diff --git a/src/espchrono.h b/src/espchrono.h index eaaa780..5f0e32d 100644 --- a/src/espchrono.h +++ b/src/espchrono.h @@ -195,6 +195,7 @@ DateTime toDateTime(std::chrono::microseconds ts); DateTime toDateTime(utc_clock::time_point ts); LocalDateTime toDateTime(local_clock::time_point ts); utc_clock::time_point fromDateTime(DateTime ts); +local_clock::time_point fromDateTime(LocalDateTime ts); std::expected parseDateTime(std::string_view str); @@ -212,4 +213,7 @@ std::string toString(milliseconds32 val); std::string toString(seconds32 val); std::string toString(minutes32 val); std::string toString(hours32 val); + +time_t toTimeT(utc_clock::time_point ts); +time_t toTimeT(local_clock::time_point ts); } // namespace espchrono