如何使用 c++20 chrono 将 "2016-Dec-31 23:59:60" UTC 时间转换为本地时间并打印正确的闰秒?



时间点" 2016-12-31 23:59:60 ";是一个有效的时间。在"1970- jan -1"之后的1483228826秒。":60";在秒的显示是正确的,因为在那里插入了一个闰秒(参见wikipedia闰秒)。

我的问题:我如何将这个时间的std::chrono::utc_clock::time_point转换为本地时间(或任何时区)并打印它,包括":60"第二部分呢?

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};

我的问题是:负责处理时区的zoned_time,只接受sys_time,不接受utc_time。但是sys_time忽略闰秒。

如果我在构建zoned_time之前将utc_time转换为sys_time,我的输出将是"…23:59:59"而闰秒就丢失了。

auto local = zoned_time{"Europe/Berlin", clock_cast<system_clock>(then));
cout << std::format("{}", time_point_cast<seconds>(local));

我认为即使在当地时间也应该显示闰秒。毕竟闰日也显示在当地时间里。

不幸的是,没有干净的方法可以做到这一点。使用的时区数据库不识别闰秒。

然而,总是有解决问题的方法。

对于seconds精度输出,通过运行thenget_leap_second_info来找出then是否指向闰秒是相当容易的:

utc_seconds then{};
then += 1483228826s;
cout << format("{}", then) << 'n';
auto local = zoned_time{"Europe/Berlin", clock_cast<system_clock>(then)};
auto [is_leap_second, elapsed] = get_leap_second_info(then);
if (is_leap_second)
cout << format("{:%F %H:%M:60}", local) << 'n';
else
cout << format("{}", local) << 'n';

输出:

2017-01-01 00:59:60

这可以扩展到亚秒精度,但只是有点混乱。这里是毫秒:

utc_time<milliseconds> then{};
then += 1483228826023ms;
cout << format("{}", then) << 'n';
auto local = zoned_time{"Europe/Berlin", clock_cast<system_clock>(then)};
auto [is_leap_second, elapsed] = get_leap_second_info(then);
if (is_leap_second)
{
cout << format("{:%F %H:%M:60.}", local);
cout << setfill('0') << setw(3) << (then-floor<seconds>(then))/1ms << 'n';
}
else
cout << format("{}", local) << 'n';

输出:

2017-01-01 00:59:60.023

所以简而言之,找出你是否在闰秒。如果不是,就打印当地时间。否则,硬连接":60",并计算/格式化子秒(如果适用)。

最新更新