How do I convert a std::chrono::time_point to long and back?

I need to convert std::chrono::time_point to and from a long type (integer 64 bits). I´m starting working with std::chrono ...

Here is my code:

int main ()
{
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();


auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long duration = value.count();




std::chrono::duration<long> dur(duration);


std::chrono::time_point<std::chrono::system_clock> dt(dur);


if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}

This code compiles, but does not show success.

Why is dt different than now at the end?

What is missing on that code?

141572 次浏览

time_point对象 只支持其他 time_pointduration对象的算术。

您需要将您的 long转换为指定单位的 duration,然后您的代码应该能够正常工作。

std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

这是一个伟大的地方 auto:

auto now = std::chrono::system_clock::now();

既然你想以 millisecond的精度传输,那么最好在 time_point中进行隐蔽操作:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_ms是一个 time_point,基于 system_clock,但与 milliseconds的精度,而不是你的 system_clock的任何精度。

auto epoch = now_ms.time_since_epoch();

epoch现在有类型 std::chrono::milliseconds。下面的语句基本上变成了 no-op (只是复制一个副本,不进行转换) :

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

这里:

long duration = value.count();

在您和我的代码中,duration都保存着自 system_clock时代以来的 milliseconds的编号。

这个:

std::chrono::duration<long> dur(duration);

创建一个用 long表示的 duration,精度为 seconds。这有效地将 reinterpret_cast中保持在 value中的 milliseconds发送到 seconds。这是逻辑错误。正确的代码应该是:

std::chrono::milliseconds dur(duration);

这句话:

std::chrono::time_point<std::chrono::system_clock> dt(dur);

创建一个基于 system_clocktime_point,能够保持与 system_clock本机精度相同的精度(通常比毫秒精度更高)。然而,运行时值将正确地反映持有的整数毫秒数(假设我对 dur类型的修正)。

不过,即使进行了修正,这种测试(几乎总是)也会失败:

if (dt != now)

因为 dt持有 milliseconds的整数,而 now持有比 millisecond(例如 microsecondsnanoseconds)更精细的蜱的整数。因此,只有在极少数情况下,system_clock::now()返回 milliseconds的整数,测试才能通过。

但你可以:

if (dt != now_ms)

现在你将可靠地得到你所期望的结果。

Putting it all together:

int main ()
{
auto now = std::chrono::system_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);


auto value = now_ms.time_since_epoch();
long duration = value.count();


std::chrono::milliseconds dur(duration);


std::chrono::time_point<std::chrono::system_clock> dt(dur);


if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}

就我个人而言,我发现所有的 std::chrono都过于冗长,因此我会将其编码为:

int main ()
{
using namespace std::chrono;
auto now = system_clock::now();
auto now_ms = time_point_cast<milliseconds>(now);


auto value = now_ms.time_since_epoch();
long duration = value.count();


milliseconds dur(duration);


time_point<system_clock> dt(dur);


if (dt != now_ms)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}

Which will reliably output:

Success.

最后,我建议消除临时代码,将 time_point和整数类型之间的代码转换减少到最低限度。这些转换是危险的,因此操作裸积分类型的代码越少越好:

int main ()
{
using namespace std::chrono;
// Get current time with precision of milliseconds
auto now = time_point_cast<milliseconds>(system_clock::now());
// sys_milliseconds is type time_point<system_clock, milliseconds>
using sys_milliseconds = decltype(now);
// Convert time_point to signed integral type
auto integral_duration = now.time_since_epoch().count();
// Convert signed integral type to time_point
sys_milliseconds dt{milliseconds{integral_duration}};
// test
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}

上面的主要危险是 没有在回到 time_point的路上将 integral_duration解释为 milliseconds。降低这种风险的一种可能方法是写下:

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

这样可以降低风险,只需确保在退出时使用 sys_milliseconds,以及在返回时使用 sys_milliseconds的两个地方。

再举一个例子: 假设您希望转换成一个积分,它表示 system_clock支持的任何持续时间(微秒,10(西班牙语)的微秒或纳秒)。然后您就不必像上面那样指定毫秒了。该守则简化为:

int main ()
{
using namespace std::chrono;
// Get current time with native precision
auto now = system_clock::now();
// Convert time_point to signed integral type
auto integral_duration = now.time_since_epoch().count();
// Convert signed integral type to time_point
system_clock::time_point dt{system_clock::duration{integral_duration}};
// test
if (dt != now)
std::cout << "Failure." << std::endl;
else
std::cout << "Success." << std::endl;
}

这是可行的,但是如果在一个平台上运行一半的转换(输出到积分) ,而在另一个平台上运行另一半的转换(从积分到积分) ,那么就存在这样的风险,即 system_clock::duration对这两种转换的精度不同。

我还要指出,有两种方法可以得到时间点的 ms 数。我不确定哪一个更好,我已经对它们进行了基准测试,它们的性能都是一样的,所以我想这只是个人偏好的问题。也许霍华德可以插句话:

auto now = system_clock::now();


//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();


//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();

第一个在我脑海里从左到右读得更清楚。

作为一句话:

long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();