以下是如何进行转换,既不使用手动转换因子,也不依赖于
time_t
的未指定舍入模式:
timeval
to_timeval(std::chrono::system_clock::time_point tp)
{
using namespace std::chrono;
auto s = time_point_cast<seconds>(tp);
if (s > tp)
s = s - seconds{1};
auto us = duration_cast<microseconds>(tp - s);
timeval tv;
tv.tv_sec = s.time_since_epoch().count();
tv.tv_usec = us.count();
return tv;
}
std::chrono::system_clock::time_point
to_time_point(timeval tv)
{
using namespace std::chrono;
return system_clock::time_point{seconds{tv.tv_sec} + microseconds{tv.tv_usec}};
}
to_timeval
会确保向下取整tp
(如果它是负数)。POSIX规范在这方面有点含糊,但我认为timeval
表示先于纪元的时间点,其tv_sec
值为负,然后tv_usec
值为正。然后可以简单地找到自上一个second
以来的microseconds
。
如果我的假设不正确(并且可以找到更精确的POSIX规范),<chrono>
有能力模拟任何它想要的东西。
反向转换非常易读,做了不需要注释。
这一切都可以像这样进行测试:
timeval
make_timeval(time_t s, long us)
{
timeval tv;
tv.tv_sec = s;
tv.tv_usec = us;
return tv;
}
bool
operator==(timeval x, timeval y)
{
return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}
int
main()
{
using namespace std::chrono;
assert(make_timeval(0, 0) == to_timeval(system_clock::time_point{}));
assert(make_timeval(1, 0) == to_timeval(system_clock::time_point{seconds{1}}));
assert(make_timeval(1, 400000) == to_timeval(system_clock::time_point{seconds{1} + microseconds{400000}}));
assert(make_timeval(-1, 400000) == to_timeval(system_clock::time_point{seconds{-1} + microseconds{400000}}));
assert(to_time_point(make_timeval(0, 0)) == system_clock::time_point{});
assert(to_time_point(make_timeval(1, 0)) == system_clock::time_point{seconds{1}});
assert(to_time_point(make_timeval(1, 400000)) == system_clock::time_point{seconds{1} + microseconds{400000}});
assert(to_time_point(make_timeval(-1, 400000)) == system_clock::time_point{seconds{-1} + microseconds{400000}});
}
这一切都基于这样一个假设: timeval
和 system_clock
的时代是相同的。虽然没有规定,但对于所有现有的实现都是正确的。希望我们能在不久的将来统一这个现有的惯例。
请注意,在 POSIX 中,timeval
既用作time_point
,也用作duration
。因此,如果timeval
当前表示时间间隔,则to_time_point
可能会导致运行时错误。而如果客户端将结果解释为时间间隔,则to_timeval
可能会导致运行时错误。
dateTime.tv_sec
和dateTime.tv_usec
,因为目标是得到一个有效的timeval
结构。 - Kyle Strandmillisecs.count()/1000l;
和dest.tv_usec=millisecs.count()%1000l;
中的l
明显是不必要的。这只是一个小问题。 - chux - Reinstate Monica