The point in time "2016-Dec-31 23:59:60" is a valid time. It is 1483228826 seconds after "1970-Jan-1". The ":60" in the seconds display is correct, because a leap second was inserted there (see wikipedia leap seconds).
My Question: How do I convert a std::chrono::utc_clock::time_point
with this time to local time (or any timezone) and print it including the ":60" for the seconds part?
std::chrono::utc_clock::time_point then;
then += seconds(1483228826);
// Output: 2016-12-31 23:59:60
cout << std::format("{}", time_point_cast<seconds>(then));
// Now convert it to local time
// But this will fail, since zoned_time requires a sys_time
auto local = zoned_time{"Europe/Berlin", then};
My problem is: zoned_time
, which is responsible for handling time zones, only accepts a sys_time
, not a utc_time
. But sys_time
ignores leap seconds.
If I convert my utc_time
to sys_time
before constructing a zoned_time
, my output will be "..23:59:59" and the leap second is lost.
auto local = zoned_time{"Europe/Berlin", clock_cast<system_clock>(then));
cout << std::format("{}", time_point_cast<seconds>(local));
I think the leap second should be shown even in local time. The leap day after all is also shown in local time.
Unfortunately there is no clean way to do this. The time zone database that is used does not recognize leap seconds.
However there is always a way to work around things.
For
seconds
precision output it is fairly easy to just brute-force things by runningthen
throughget_leap_second_info
to find out ifthen
points into a leap second:Output:
This can be extended to subsecond precision, but is just a little messier. Here it is for milliseconds:
Output:
So in a nutshell, find out if you're in a leap second. If you're not just print the local time. Otherwise hard-wire the
":60"
, and compute/format the subseconds if applicable.