如何将 std::chrono::time_point 转换为 long 并返回?

新手上路,请多包涵

我需要将 std::chrono::time_point 转换为 long 类型(整数 64 位)。我开始使用 std::chrono

这是我的代码:

 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;
}

此代码编译,但未显示成功。

为什么最后 --- 与 now dt 不同?

该代码缺少什么?

原文由 Mendes 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答
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 is a time_point , based on system_clock , but with the precision of milliseconds instead of whatever precision your system_clock 有。

 auto epoch = now_ms.time_since_epoch();

epoch 现在有类型 std::chrono::milliseconds 。下一条语句本质上变成了无操作(仅进行复制而不进行转换):

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

这里:

 long duration = value.count();

在您和我的代码中, duration 拥有自 milliseconds 的时代以来的 system_clock 的数量。

这个:

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

创建一个 durationlong 表示,精度为 seconds 。这实际上是 reinterpret_cast s milliseconds 保存在 valueseconds 。这是一个逻辑错误。正确的代码如下所示:

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

这一行:

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

创建一个 time_point 基于 system_clock ,能够保持 system_clock 的本机精度(通常比毫秒)。但是,运行时值将正确反映整数毫秒数(假设我更正了 dur 的类型)。

即使进行了更正,此测试也会(几乎总是)失败:

 if (dt != now)

因为 dt 拥有整数个 milliseconds ,但是 now 拥有比 a millisecond 更精细的整数个刻度 microseconds 67eebeeabd0351a ---nanoseconds )。因此,只有在 system_clock::now() 返回整数 milliseconds 的极少数情况下,测试才会通过。

但您可以改为:

 if (dt != now_ms)

现在,您将可靠地获得预期的结果。

把它们放在一起:

 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;
}

这将可靠地输出:

 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;
}

上面的主要危险 不是 在返回 milliseconds 的路上将 integral_duration 解释为 time_point 。减轻这种风险的一种可能方法是编写:

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

这将风险降低到只需确保您在退出时使用 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 两者的精度不同的风险转换。

原文由 Howard Hinnant 发布,翻译遵循 CC BY-SA 3.0 许可协议

time_point 对象 仅支持与其他 time_pointduration 对象的算术运算。

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

原文由 Mr. Llama 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题