如何安全度过clock_cast天?
How to safely clock_cast days?
我正在使用 HowardHinnant/date 代替 Clang/GCC 中尚不可用的新 C++20 calendar/timezone 功能。我的问题同样适用于两种实现方式:How do I safely clock_cast
time_point
s having days
duration?
当我尝试时:
using namespace date; // or using std::chrono in C++20
tai_time<days> tai{days{42}};
sys_days sys = clock_cast<std::chrono::system_clock>(tai);
最后一条语句出现“无可行转换”错误。事实证明,结果使用的持续时间是 common_type<days, seconds>
,它来自转换中使用的 utc_clock::to_sys()
。常见的时长类型是std::chrono::seconds
,所以不能直接转换成days
时长是正常的。
如果我使用显式 duration_cast
:
我可以让它编译
using namespace date; // or using std::chrono in C++20
tai_time<days> tai{days{42}};
auto casted = clock_cast<std::chrono::system_clock>(tai);
sys_days sys{std::chrono::duration_cast<days>(casted.time_since_epoch())};
...但我担心结果可能会因截断而偏离一天(尤其是对于纪元之前的日期)。这是做我想做的事情的正确方法吗?我应该使用 floor
而不是 duration_cast
吗?
为什么 utc_clock::to_sys()
里还有一个 std::common_type_t<Duration, std::chrono::seconds>
?它不应该只是 return 相同的持续时间类型吗?
之所以clock_cast
坚持至少seconds
的精度是因为system_clock
和tai_clock
的纪元之间的偏移精度为seconds
:
auto diff = sys_days{} - clock_cast<system_clock>(tai_time<days>{});
cout << diff << " == " << duration<double, days::period>{diff} << '\n';
输出:
378691210s == 4383.000116d
所以 days
精确转换会造成损失。这是另一种看待它的方式:
cout << clock_cast<tai_clock>(sys_days{2021_y/June/1}) << '\n';
输出:
2021-06-01 00:00:37
即TAI is currently 37 seconds ahead of system_clock
按日历计算。
如果你只想要日期,我推荐round<days>(result)
:
cout << round<days>(clock_cast<tai_clock>(sys_days{2021_y/June/1})) << '\n';
输出:
2021-06-01 00:00:00
可以想象在一个方向上使用 floor
而在另一个方向上使用 ceil
,但这很容易出错。 round
会很好,因为与整数天数的偏移量目前只有 37 秒并且增长非常缓慢。
我正在使用 HowardHinnant/date 代替 Clang/GCC 中尚不可用的新 C++20 calendar/timezone 功能。我的问题同样适用于两种实现方式:How do I safely clock_cast
time_point
s having days
duration?
当我尝试时:
using namespace date; // or using std::chrono in C++20
tai_time<days> tai{days{42}};
sys_days sys = clock_cast<std::chrono::system_clock>(tai);
最后一条语句出现“无可行转换”错误。事实证明,结果使用的持续时间是 common_type<days, seconds>
,它来自转换中使用的 utc_clock::to_sys()
。常见的时长类型是std::chrono::seconds
,所以不能直接转换成days
时长是正常的。
如果我使用显式 duration_cast
:
using namespace date; // or using std::chrono in C++20
tai_time<days> tai{days{42}};
auto casted = clock_cast<std::chrono::system_clock>(tai);
sys_days sys{std::chrono::duration_cast<days>(casted.time_since_epoch())};
...但我担心结果可能会因截断而偏离一天(尤其是对于纪元之前的日期)。这是做我想做的事情的正确方法吗?我应该使用 floor
而不是 duration_cast
吗?
为什么 utc_clock::to_sys()
里还有一个 std::common_type_t<Duration, std::chrono::seconds>
?它不应该只是 return 相同的持续时间类型吗?
之所以clock_cast
坚持至少seconds
的精度是因为system_clock
和tai_clock
的纪元之间的偏移精度为seconds
:
auto diff = sys_days{} - clock_cast<system_clock>(tai_time<days>{});
cout << diff << " == " << duration<double, days::period>{diff} << '\n';
输出:
378691210s == 4383.000116d
所以 days
精确转换会造成损失。这是另一种看待它的方式:
cout << clock_cast<tai_clock>(sys_days{2021_y/June/1}) << '\n';
输出:
2021-06-01 00:00:37
即TAI is currently 37 seconds ahead of system_clock
按日历计算。
如果你只想要日期,我推荐round<days>(result)
:
cout << round<days>(clock_cast<tai_clock>(sys_days{2021_y/June/1})) << '\n';
输出:
2021-06-01 00:00:00
可以想象在一个方向上使用 floor
而在另一个方向上使用 ceil
,但这很容易出错。 round
会很好,因为与整数天数的偏移量目前只有 37 秒并且增长非常缓慢。