|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
#include "espchrono.h"
|
|
|
|
|
|
|
|
|
|
// 3rdparty lib includes
|
|
|
|
|
#include <fmt/format.h>
|
|
|
|
|
// system includes
|
|
|
|
|
#include <format>
|
|
|
|
|
|
|
|
|
|
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<DateTime, std::string> parseDateTime(std::string_view str)
|
|
|
|
|
{
|
|
|
|
|
// both valid:
|
|
|
|
@ -234,7 +248,7 @@ std::expected<DateTime, std::string> 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<std::chrono::seconds, std::string> 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<std::chrono::seconds>(ts.time_since_epoch()).count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time_t toTimeT(local_clock::time_point ts)
|
|
|
|
|
{
|
|
|
|
|
return std::chrono::duration_cast<std::chrono::seconds>(ts.time_since_epoch()).count();
|
|
|
|
|
}
|
|
|
|
|
} // namespace espchrono
|
|
|
|
|