使用chrono c++库计算时间戳的差异

Posted

技术标签:

【中文标题】使用chrono c++库计算时间戳的差异【英文标题】:Using chrono c++ library to calculate difference of timestamp 【发布时间】:2015-08-20 06:45:57 【问题描述】:

从here跟进

我试图通过查看数据的时间戳来查看我的数据是否存在 120 秒,因此我在使用 std::chrono 包的库项目中有以下小代码:

uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

// some logging to print out above values
LOG4CXX_WARN(logger, "data logging, now: " << now << ", data holder timestamp: " << data_holder->getTimestamp() << ", is_old: " << is_old << ", difference: " << (now -         data_holder->getTimestamp()));

在上面的代码中data_holder-&gt;getTimestamp()uint64_t,它以毫秒为单位返回时间戳。

现在当我打印出now 变量值时,我看到了这个433425679,当我打印出data_holder-&gt;getTimestamp() 值时1437943796841,现在和数据持有者时间戳的差异为18446742636199180454如下日志所示:

2015-07-26 13:49:56,850 WARN 0x7fd050bc9700 simple_process - data logging, now: 433425679 , data holder timestamp: 1437943796841 , is_old: 1 , difference: 18446742636199180454

现在,如果我使用纪元转换器转换数据持有者时间戳1437943796841,我会看到:

Your time zone: 7/26/2015, 1:49:56 PM

这与日志2015-07-26 13:49:56,850 WARN 中显示的时间戳完全相同,因此这意味着我的数据看起来不是 120 秒的旧数据。如果是,那为什么我看到is_old 的值是1

看起来data_holder-&gt;getTimestamp() 值来自我们代码库中的以下代码,然后我们将其进行比较以进行 120 秒旧数据检查。

// is this the problem?
struct timeval val;
gettimeofday(&val, NULL);
uint64_t time_ms = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;

现在仔细阅读了 C++ 中的各种时钟实现,看起来我们应该使用相同的时钟来进行比较。

我上面计算data_holder-&gt;getTimestamp()值的代码有问题吗?因为我没有使用steady_clock,所以纪元时间会有所不同,这就是我看到这个问题的原因?

现在我的问题是 - 我应该使用什么代码来解决这个问题?我应该使用steady_clock 以及data_holder-&gt;getTimestamp() 代码吗?如果是,那么正确的方法是什么?

同样的代码在 Ubuntu 12 中运行良好,但在 Ubuntu 14 中运行不正常。我正在运行所有静态链接库。对于 Ubuntu 12,代码在运行 4.7.3 编译器的 Ubuntu 12 上编译,对于 Ubuntu 14,代码在运行 4.8.2 编译器的 Ubuntu 14 上编译。

【问题讨论】:

std::chrono::steady_clock 与挂钟时间无关 (std::chrono::system_clock)。换句话说,您无法将稳定时钟的时间与系统(挂钟)时钟的时间进行比较。 gettimeofday 返回 wall 时钟时间。 我明白了,那么我们应该在这里做什么?我猜这两个代码中的任何一个都会改变吗? 【参考方案1】:

两者使用相同的时钟。如果您的时间戳需要在应用程序的运行中保持含义,您必须使用system_clock,而不是steady_clock。如果您的时间戳仅在一次运行中有意义,您可以使用steady_clock

steady_clock 就像一个“秒表”。你可以用它来计时,但你不能用它来获取当前时间。

DataHolder::DataHolder()
    : timestamp_system_clock::now()
    

system_clock::time_point
DataHolder::getTimestamp()

    return timestamp_;


bool is_old = minutes2 < system_clock::now() - data_holder->getTimestamp();

在 C++14 中,您可以将其缩短为:

bool is_old = 2min < system_clock::now() - data_holder->getTimestamp();

请使用&lt;chrono&gt;。 请勿使用count()time_since_epoch()(调试目的除外)。 请勿使用1000120 等转化系数。

违反上述准则会将编译时错误转变为运行时错误。编译时错误是你的朋友。 &lt;chrono&gt; 在编译时捕获许多错误。一旦您摆脱了&lt;chrono&gt; 的类型安全性(例如,通过使用count()),您就可以使用相当于计时的汇编语言进行编程。而&lt;chrono&gt; 的类型安全系统的空间/时间开销为零。

【讨论】:

【参考方案2】:

您应该明确地为两者使用相同的时间函数。

我建议更改创建 getTimestamp() 值的方式(例如,通过使用 chrono::system_clock)或比较时间戳的方式。

干净的方法是像这样改变它:

struct timeval val;
gettimeofday(&val, NULL);
uint64_t now = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

反之亦然

1.改变getTimestamp()值的创建方式

long long time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

2.调整比较功能

long long now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

【讨论】:

以上是关于使用chrono c++库计算时间戳的差异的主要内容,如果未能解决你的问题,请参考以下文章

什么是两台机器之间时间戳的最佳 c++ chrono 函数

计算两个时间戳之间的差异并获得 unix 时间戳的差异

分组并计算时间戳的差异

带有 UNIX 时间戳的 MySQL 表 - 按时间戳排序并计算一行与前一行之间的差异

C++ 使用 chrono 库处理日期和时间

计算同一张表中SQL中两个时间戳的差值