Skip to content

Commit

Permalink
UTC conversion improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkvdb committed Aug 27, 2024
1 parent ae3c85e commit 49ce5a4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 44 deletions.
27 changes: 15 additions & 12 deletions chrono.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,30 +175,33 @@ std::optional<local_time_point> local_time_point_from_string(std::string_view st
}

#ifdef HAVE_CPP20_CHRONO
std::optional<time_point> localtime_to_utc(time_point dt, std::chrono::choose* choice)
std::optional<time_point> localtime_to_utc(local_time_point dt, std::optional<choose> choice)
{
auto ymd = chrono::to_year_month_day(dt);
auto tod = chrono::time_of_day(dt); // Yields time_of_day type
if (choice.has_value()) {
return localtime_to_utc(zoned_time(std::chrono::current_zone(), dt, *choice));
} else {
return localtime_to_utc(zoned_time(std::chrono::current_zone(), dt));
}
}

auto tp = std::chrono::local_days{ymd} + tod.hours() + tod.minutes() + tod.seconds();
auto z = std::chrono::current_zone();
std::optional<time_point> localtime_to_utc(zoned_time zt)
{
auto localTimePoint = zt.get_local_time();

std::optional<time_point> utcTime;
auto i = z->get_info(tp);
auto i = zt.get_time_zone()->get_info(localTimePoint);
switch (i.result) {
case std::chrono::local_info::unique: {
std::chrono::zoned_time<std::chrono::seconds> zt(z, tp); //"Europe/Brussels"
utcTime = std::optional<time_point>(zt.get_sys_time());
break;
}
case std::chrono::local_info::ambiguous: {
if (choice) {
std::chrono::zoned_time<std::chrono::seconds> zt(z, tp, *choice);
utcTime = std::optional<time_point>(zt.get_sys_time());
}
Log::warn("Ambiguous time point, taking the latest option");
utcTime = std::optional<time_point>(i.second.begin);
break;
}
case std::chrono::local_info::nonexistent:
Log::error("Non existing timepoint");
break;
default:
break;
Expand All @@ -207,7 +210,7 @@ std::optional<time_point> localtime_to_utc(time_point dt, std::chrono::choose* c
return utcTime;
}
#else
std::optional<time_point> localtime_to_utc(time_point dt, date::choose* choice)
std::optional<time_point> localtime_to_utc(local_time_point dt, std::optional<choose> choice)
{
auto ymd = chrono::to_year_month_day(dt);
auto tod = chrono::time_of_day(dt); // Yields time_of_day type
Expand Down
26 changes: 3 additions & 23 deletions chrono.natvis
Original file line number Diff line number Diff line change
@@ -1,31 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="std::chrono::time_point&lt;std::chrono::system_clock,std::chrono::duration&lt;__int64,std::ratio&lt;1,10000000&gt; &gt; &gt;">
<DisplayString>
year: {
1969 +
4 * (((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) / (365 * 3 + 366)) +
(((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) % (365 * 3 + 366) &lt;= (3 * 365) ? (((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) % (365 * 3 + 366)) / 365 : 3)
} DoY: {
((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) % (365 * 3 + 366) &lt;= (3 * 365) ? (((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) % (365 * 3 + 366)) % 365 : (((_MyDur._MyRep / (24 * 60 * 60 * 10000000ull)) + 365) % (365 * 3 + 366)) - 365 * 3
} {
(_MyDur._MyRep % (24 * 60 * 60 * 10000000ull))/(10 * 60 * 60 * 10000000ull)}{(_MyDur._MyRep % (4 * 60 * 60 * 10000000ull))/(60 * 60 * 10000000ull)}:{(_MyDur._MyRep % (60 * 60 * 10000000ull))/(10 * 60 * 10000000ull)}{(_MyDur._MyRep % (10 * 60 * 10000000ull)) / (60 * 10000000ull)}:{(_MyDur._MyRep % (60 * 10000000ull)) / (10 * 10000000ull)}{(_MyDur._MyRep % (10 * 10000000ull)) / 10000000ull}.{(_MyDur._MyRep % 10000000) / 1000000}{(_MyDur._MyRep % 1000000) / 100000}{(_MyDur._MyRep % 100000) / 10000}{(_MyDur._MyRep % 10000) / 1000}{(_MyDur._MyRep % 1000) / 100}{(_MyDur._MyRep % 100) / 10}{_MyDur._MyRep % 10
} hh:mm:ss
</DisplayString>
<Expand/>
<!-- This won't display dates outside of the range of 1901 to 2099 properly (leap years are dumb), but for dates around the present it's fine-->
<DisplayString>{1968+4*((_MyDur._MyRep/864000000000ll+731)/1461)+((((_MyDur._MyRep/864000000000ll+731)%1461)&lt;366)?0:(((_MyDur._MyRep/864000000000ll+731)%1461-1)/365))}/{char(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365+(((((_MyDur._MyRep/864000000000ll)+731)%1461)&lt;366)?1:0))/31+1):(3+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)/153)*5+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)/61*2+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)%61/31))%10+((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365+(((((_MyDur._MyRep/864000000000ll)+731)%1461)&lt;366)?1:0))/31+1):(3+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)/153)*5+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)/61*2+(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)%61/31))/10*16),nvoxb}/{char(((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365+(((((_MyDur._MyRep/864000000000ll)+731)%1461)&lt;366)?1:0))%31+1):((((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)%61%31+1))%10+((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365+(((((_MyDur._MyRep/864000000000ll)+731)%1461)&lt;366)?1:0))%31+1):((((((_MyDur._MyRep/864000000000ll+731)%1461-1)%365)-59)%153)%61%31+1))/10*16),nvoxb} {char(((_MyDur._MyRep/36000000000ll)%24)%10+((_MyDur._MyRep/36000000000ll)%24)/10*16),nvoxb}:{char(((_MyDur._MyRep/600000000ll)%60)%10+((_MyDur._MyRep/600000000ll)%60)/10*16),nvoxb}:{char(((_MyDur._MyRep/10000000ll)%60)%10+((_MyDur._MyRep/10000000ll)%60)/10*16),nvoxb}.{short((_MyDur._MyRep/1000)%10+((_MyDur._MyRep/10000)%10)*16+((_MyDur._MyRep/100000)%10)*256+((_MyDur._MyRep/1000000)%10)*4096),nvoxb}</DisplayString>
</Type>
<Type Name="std::chrono::time_point&lt;std::chrono::system_clock,std::chrono::duration&lt;__int64,std::ratio&lt;1,1000&gt; &gt; &gt;">
<DisplayString>
year: {
1969 +
4 * (((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) / (365 * 3 + 366)) +
(((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) % (365 * 3 + 366) &lt;= (3 * 365) ? (((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) % (365 * 3 + 366)) / 365 : 3)
} DoY: {
((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) % (365 * 3 + 366) &lt;= (3 * 365) ? (((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) % (365 * 3 + 366)) % 365 : (((_MyDur._MyRep / (24 * 60 * 60 * 1000ull)) + 365) % (365 * 3 + 366)) - 365 * 3
} {
(_MyDur._MyRep % (24 * 60 * 60 * 1000ull))/(10 * 60 * 60 * 1000ull)}{(_MyDur._MyRep % (4 * 60 * 60 * 1000ull))/(60 * 60 * 1000ull)}:{(_MyDur._MyRep % (60 * 60 * 1000ull))/(10 * 60 * 1000ull)}{(_MyDur._MyRep % (10 * 60 * 1000ull)) / (60 * 1000ull)}:{(_MyDur._MyRep % (60 * 1000ull)) / (10 * 1000ull)}{(_MyDur._MyRep % (10 * 1000ull)) / 1000ull}.{(_MyDur._MyRep % 1000) / 100}{(_MyDur._MyRep % 100) / 10
} hh:mm:ss
</DisplayString>
<DisplayString>{1968+4*((_MyDur._MyRep/86400000ll+731)/1461)+((((_MyDur._MyRep/86400000ll+731)%1461)&lt;366)?0:(((_MyDur._MyRep/86400000ll+731)%1461-1)/365))}/{char(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/86400000ll+731)%1461-1)%365+(((((_MyDur._MyRep/86400000ll)+731)%1461)&lt;366)?1:0))/31+1):(3+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)/153)*5+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)/61*2+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)%61/31))%10+((((_MyDur._MyRep/86400000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/86400000ll+731)%1461-1)%365+(((((_MyDur._MyRep/86400000ll)+731)%1461)&lt;366)?1:0))/31+1):(3+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)/153)*5+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)/61*2+(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)%61/31))/10*16),nvoxb}/{char(((((_MyDur._MyRep/86400000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/86400000ll+731)%1461-1)%365+(((((_MyDur._MyRep/86400000ll)+731)%1461)&lt;366)?1:0))%31+1):((((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)%61%31+1))%10+((((_MyDur._MyRep/86400000ll+731)%1461-1)%365&lt;59)?((((_MyDur._MyRep/86400000ll+731)%1461-1)%365+(((((_MyDur._MyRep/86400000ll)+731)%1461)&lt;366)?1:0))%31+1):((((((_MyDur._MyRep/86400000ll+731)%1461-1)%365)-59)%153)%61%31+1))/10*16),nvoxb} {char(((_MyDur._MyRep/3600000ll)%24)%10+((_MyDur._MyRep/3600000ll)%24)/10*16),nvoxb}:{char(((_MyDur._MyRep/60000ll)%60)%10+((_MyDur._MyRep/60000ll)%60)/10*16),nvoxb}:{char(((_MyDur._MyRep/1000ll)%60)%10+((_MyDur._MyRep/1000ll)%60)/10*16),nvoxb}.{short((_MyDur._MyRep/1000)%10+((_MyDur._MyRep/10000)%10)*16+((_MyDur._MyRep/100000)%10)*256+((_MyDur._MyRep/1000000)%10)*4096),nvoxb}</DisplayString>
<Expand/>
</Type>
</AutoVisualizer>
32 changes: 23 additions & 9 deletions include/infra/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ using year_month_day = std::chrono::year_month_day;
using sys_days = std::chrono::sys_days;
using date_point = std::chrono::time_point<std::chrono::system_clock, days>;
using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
using zoned_time = std::chrono::zoned_time<std::chrono::milliseconds>;

using local_seconds = std::chrono::local_seconds;
using local_date_point = std::chrono::local_days;
Expand Down Expand Up @@ -57,6 +58,7 @@ using year_month_day = date::year_month_day;
using sys_days = date::sys_days;
using date_point = std::chrono::time_point<std::chrono::system_clock, days>;
using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
using zoned_time = date::zoned_time<std::chrono::milliseconds>;

using local_seconds = date::local_seconds;
using local_date_point = date::local_days;
Expand Down Expand Up @@ -88,6 +90,7 @@ local_date_point date_from_time_point(local_time_point tp);
#ifdef HAVE_CPP20_CHRONO
std::chrono::hh_mm_ss<std::chrono::milliseconds> time_of_day(time_point tp);
std::chrono::hh_mm_ss<std::chrono::milliseconds> time_of_day(local_time_point tp);

std::chrono::year_month_day to_year_month_day(time_point tp);
std::chrono::year_month_day to_year_month_day(local_time_point tp);

Expand Down Expand Up @@ -134,8 +137,19 @@ std::string to_string(local_time_point tp);
template <typename Clock, typename Duration>
std::string to_string(std::string_view format, std::chrono::time_point<Clock, Duration> tp)
{
std::time_t time = Clock::to_time_t(tp);
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), fmt::localtime(time));
#ifdef HAVE_CPP20_CHRONO
if constexpr (std::is_same_v<Clock, std::chrono::utc_clock>) {
std::time_t time = std::chrono::system_clock::to_time_t(std::chrono::utc_clock::to_sys(tp));
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), tp);
#else
if constexpr (std::is_same_v<Clock, date::utc_clock>) {
std::time_t time = std::chrono::system_clock::to_time_t(date::utc_clock::to_sys(tp));
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), tp);
#endif
} else {
std::time_t time = Clock::to_time_t(tp);
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), fmt::localtime(time));
}
}

/*! Converts a string to a time point using the provided format specification
Expand All @@ -157,8 +171,11 @@ std::string to_utc_string(std::chrono::time_point<Clock, Duration> tp)
template <typename Clock, typename Duration>
std::string to_utc_string(std::string_view format, std::chrono::time_point<Clock, Duration> tp)
{
std::time_t time = Clock::to_time_t(tp);
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), fmt::gmtime(time));
if constexpr (std::is_same_v<Clock, std::chrono::utc_clock>) {
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), tp);
} else {
return fmt::format(fmt::runtime(fmt::format("{{:{}}}", format)), fmt::gmtime(tp));
}
}

inline std::string to_string(std::string_view format, chrono::local_time_point tp)
Expand All @@ -172,11 +189,8 @@ inline std::string to_string(std::string_view format, chrono::local_time_point t
#endif
}

#ifdef HAVE_CPP20_CHRONO
std::optional<time_point> localtime_to_utc(time_point dt, std::chrono::choose* choice = nullptr);
#else
std::optional<time_point> localtime_to_utc(time_point dt, date::choose* choice = nullptr);
#endif
std::optional<time_point> localtime_to_utc(local_time_point dt, std::optional<choose> choice);
std::optional<time_point> localtime_to_utc(zoned_time tp);

class DurationRecorder
{
Expand Down

0 comments on commit 49ce5a4

Please sign in to comment.