为什么 steady_clock::now().time_since_epoch().count() 在 Windows 上返回自重新启动以来的时间?

why does steady_clock::now().time_since_epoch().count() return time since reboot on Windows?

提问人:dmedine 提问时间:7/24/2023 最后编辑:dmedine 更新时间:7/24/2023 访问量:167

问:

Windows 10 上的以下代码:

#include <chrono>
#include <iostream>

int main(void)
{
    const auto p1 = std::chrono::system_clock::now();
    const auto p2 = std::chrono::steady_clock::now();

    std::cout << "system_clock seconds since epoch: "
        << std::chrono::duration_cast<std::chrono::seconds>(
            p1.time_since_epoch()).count()
        << '\n';

    std::cout << "steady_clock seconds since epoch: "
        << std::chrono::duration_cast<std::chrono::seconds>(
            p2.time_since_epoch()).count()
        << '\n';

    return 0;
}

输出:

system_clock seconds since epoch: 1690157550
steady_clock seconds since epoch: 434342

所以似乎计算了自上次启动以来的时间---即使我要求自 Epoch 以来的时间。对我来说,这是不正确的。自纪元以来,它没有给我时间。steady_clock

C++ 标准 C++-Chrono

评论

3赞 康桓瑋 7/24/2023
来自 cppreference:“此时钟与挂钟时间无关(例如,它可以是自上次重新启动以来的时间),最适合测量间隔。"
1赞 ALX23z 7/24/2023
你认为“时代”这个词是什么意思?
2赞 François Andrieux 7/24/2023
@dmedine 纪元只是任何定义的时间段。它不是任何一个特定时间点的名称。
1赞 dmedine 7/24/2023
@FrançoisAndrieux en.wikipedia.org/wiki/Epoch_(计算) 根据维基百科,“纪元”是一个日期,而不是一个时间段。如果“epoch”指的是某个句点,则应重命名该方法。time_since_epoch
1赞 Swift - Friday Pie 7/24/2023
steady_clock的 POSIX 模拟在类 Linux 系统和基于 FreeBSD 的嵌入式操作系统上工作相同,我遇到过计算进程启动以来时间的情况。它的目的是具有永不回退的计时器(即使系统时间可能由于某种原因而回滚,例如由于 NTP 服务的更正)

答:

7赞 Sam Varshavchik 7/24/2023 #1

C++ 标准没有对所有时钟的纪元进行任何具体定义,作为一般要求:

27.3 Cpp17时钟要求 [time.clock.req]

1时钟是由持续时间、time_point和 函数 now() 来获取currenttime_point。时钟的起源 time_point被称为时钟的纪元。

句点。一个特定的时钟有某种起源纪元,但它是什么,一般没有指定。它是为每个特定时钟指定的(如果有)。

例如,的原产地明确给出为 1970 年 1 月 1 日:system_clock

类 system_clock [time.clock.system]

[ ... ] system_clock类型的对象表示系统范围实时时钟的挂钟时间。sys_time类型的对象测量自 1970-01-01 00:00:00 UTC 以来的时间,不包括闰秒。

没有这样的要求。C++ 标准保留 未指定 的原点或纪元。给你的唯一保证是永远不会减少。从 C++ 标准:steady_clocksteady_clocksteady_clock

类 steady_clock [time.clock.steady]

[...]

类 steady_clock 的对象表示时钟,其值 time_point永远不会随着物理时间的推进和价值而减少 time_point相对于实时以稳定的速度前进。那是 时钟可能无法调整。

就是这样。没有表示与挂钟时间和任何特定的基于挂钟的起点有任何关系。因此,MS-Windows 自系统启动以来计算时间的实现在此定义的范围内。steady_clock

现在,时钟确实会在下一次启动时有效地重置自己,可以问一个问题,这是否严格符合“永不减少”的要求,但那将是一个不同的问题。到目前为止,为什么不计算秒数,因为Unix纪元,就像,是因为C++标准不需要这个。steady_clocksystem_clock

评论

0赞 dmedine 7/24/2023
很好的答案。不过,有一种评论是,人们也可以争辩说Unix的实现也违反了标准。如果 Unix 添加偏移量来(某种程度上)对齐steady_clock的输出,使其从 1 月 1 日 UTC 时刻开始计算,则该时钟将进行调整。
2赞 Sam Varshavchik 7/24/2023
但前提是情况如此:在 Unix 上只是加上一个固定的偏移量。这是非常非常不可能的。我没有看到任何证据。如果有的话,Unix 时间也可能以 1/1/1970 UTC 为纪元,但在秒内也会滴答作响,那么这仍然符合要求。请注意,C++2 单独显式定义了 。steady_clocksystem_clocksteady_clockutc_clock
0赞 dmedine 7/24/2023
是的,但它必须将分时的第一次计算与一些正偏移量联系起来,使其回到 1970 年 1 月 1 日。我建议从技术上讲,这也是一种“调整”。这似乎只是一个细节,但我认为这种不一致(无论是在规范中还是在实现对它的服从中)是错位的原因---对于我的具体问题来说,这是一个问题。
0赞 Howard Hinnant 7/24/2023
@dmedine 在不同的平台上有不同的时代会给您带来什么问题?steady_clock
1赞 Sebastian 7/24/2023
@dmedline 你能把两个时钟结合起来吗?在流程开始时计算偏移量以固定原点并使用它来保持单调?system_clocksteady_clock