我试图通过查看数据的时间戳来查看我的数据是否有120秒的历史,因此我有以下代码:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));在上面的代码中,data_holder->getTimestamp()是uint64_t,它以毫秒为单位返回时间戳。
现在,当我打印出now变量值时,我看到了这个10011360,当我打印出data_holder->getTimestamp()值,也就是1437520382241,所以现在和数据持有者时间戳的区别应该是负的,对吗?为什么它会像下面的日志中所示的那样是正的呢?
2015-07-21 16:13:02,530 WARN 0x7f35312d1700 data_check - now value: 10011360 , data holder timestamp: 1437520382241 , difference: 18446742636199180735我上面的代码看起来对吗?从上面的数据持有者时间戳来看,它看起来不是120秒前的数据,所以我觉得我的代码有问题吗?因为如果我将数据保持时间戳转换为实际时间(使用划时代转换器),然后将其与上面所示的日志时间进行比较,那么它几乎是一样的。
如上面所示,我使用的是steady_clock。这里需要使用system_clock吗?steady_clock和system_clock在外行方面的区别是什么?我正在Ubuntu14.04框上运行这段代码。
发布于 2015-07-22 04:01:08
以相反顺序回答问题:
steady_clock和system_clock在外行方面的区别是什么?
如果你手里拿着一个system_clock,你就叫它手表,它会告诉你现在是什么时候。
如果你手里拿着一个steady_clock,你会称它为秒表,它会告诉你某人跑一圈有多快,但它不会告诉你现在是什么时候。
如果你必须的话,你可以用你的手表给某人计时一圈。但是,如果你的手表(像我的)定期与另一台机器(如Boulder中的原子钟)交谈,以修正自己的时间,它可能会在计时上犯一些小错误。秒表不会犯这个错误,但它也不能告诉你正确的当前时间是什么。
我上面的代码看上去对吗?
不是的。即使它给了你合理的答案,我也不会说它是对的。不要难过,这是很多人在使用<chrono>库时犯的一个初学者错误。
对于<chrono>库,我遵循一个简单的规则。这个规则实际上是不完全正确的(因此它是一个指南)。但是,它已经足够接近,足以成为几乎总是遵循的指导方针:
不要使用
count()。
还有一个推论:
不要使用
time_since_epoch()。
<chrono>库是围绕一个类型安全系统设计的,目的是保护您免受单元转换错误的影响。如果意外尝试不安全的转换,则会在编译时捕获错误(而不是运行时错误)。
成员函数count()和time_since_epoch()是这种类型安全系统的“逃生舱口”.只在紧急情况下使用。当委员会忽略给您完成<chrono>类型的工作所需的所有工具(例如I/O),或者需要通过整数与其他定时API接口时,就会出现这种紧急情况。
检查您的代码和其他代码,以便使用count()和time_since_epoch(),并仔细检查这些函数的每一种用法:是否可以重写代码以消除它们的使用?
检查代码的第一行:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();now是time_point (来自steady_clock)。It单元是milliseconds,但此时我不确定这些单元是重要的。重要的是,now是从steady_clock检索的time_point。
auto now = steady_clock::now();你的第二行更复杂:
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));让我们从data_holder->getTimestamp()开始:如果您可以修改getTimestamp(),那么应该修改它以返回time_point而不是uint64_t。要做到这一点,您必须知道正确的单位(您所做的-毫秒),和,您将必须知道正确的时代。时代是用来测量毫秒的时间点。
在这种情况下,1437520382241ms大约是45.6年。假设这是最近的时间戳,45.6年前非常接近1970-01-01.事实证明,system_clock()的每个实现都使用1970-01-01作为它的时代(尽管每个实现与这个时代有不同的单位)。
因此,要么修改getTimestamp()以返回time_point<system_clock, milliseconds>,要么用time_point<system_clock, milliseconds>包装getTimestamp()的返回
auto dh_ts = system_clock::time_point{milliseconds{data_holder->getTimestamp()}};现在,您的第二行是:
bool is_old = (120 * 1000 < (now - dh_ts));另一个很好的指导方针是:
如果您在
<chrono>代码中看到了转换因素,那么您就错了。<chrono>是为你做转换而生的。
bool is_old = (minutes{2} < (now - dh_ts));接下来的步骤是风格化的,但是现在您的代码足够简单,可以去掉多余的括号,如果这对您有吸引力的话:
bool is_old = minutes{2} < now - dh_ts;如果您能够修改getTimestamp()以返回一个类型安全值,那么这段代码也可以如下所示:
bool is_old = minutes{2} < now - data_holder->getTimestamp();唉,不管怎样,这还是不能编译的!错误消息应该声明在now和dh_ts之间没有有效的dh_ts。
这是类型安全系统进来,以避免您运行时错误!
问题是,来自system_clock的system_clocks不能从steady_clock的time_points中减去(因为这两者有不同的时代)。所以你必须切换到:
auto now = system_clock::now();把这一切结合在一起:
#include <chrono>
#include <cstdint>
#include <memory>
struct DataHolder
{
std::chrono::system_clock::time_point
getTimestamp()
{
using namespace std::chrono;
return system_clock::time_point{milliseconds{1437520382241}};
}
};
int
main()
{
using namespace std;
using namespace std::chrono;
auto data_holder = std::unique_ptr<DataHolder>(new DataHolder);
auto now = system_clock::now();
bool is_old = minutes{2} < now - data_holder->getTimestamp();
}在C++14中,最后一行可以变得更简洁一些:
bool is_old = 2min < now - data_holder->getTimestamp();总结如下:
count() (I/O除外)。time_since_epoch() (I/O除外)。如果您在上述四点上取得成功,您很可能不会遇到任何运行时错误(但您将得到编译时错误的公平份额)。
发布于 2019-03-19 05:27:38
发布于 2015-07-22 01:13:05
第一件事
您看到正值的原因是由于无符号整数环绕。试试这个,看看:
std::cout << static_cast <uint64_t> (-1) << std::endl;getTimestamp()返回的值是预期的吗?如果不是的话,如果没有看到getTimestamp()的实现,就很难看出出了什么问题。看起来时间戳不是用同一个时钟来测量的。
稳定相对于系统时间
稳定的时钟是测量时间间隔的最佳方法。引用cppreference.com
类std::chrono::steady_clock表示一个单调的时钟。这个时钟的时间点不能随着物理时间的推移而减少。此时钟与挂钟时间无关,最适合测量间隔时间。
与system_clock不同,后者不是单调的(也就是说,如果用户更改主机上的时间,时间就会减少)。
https://stackoverflow.com/questions/31552193
复制相似问题