持久化 std::chrono time_point 实例

问题描述 投票:0回答:2

持久化 std::chrono time_point 实例然后将它们读回相同类型的另一个实例的正确方法是什么?

   typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;

   time_point_t tp = std::chrono::high_resolution_clock::now();
   serializer.write(tp);
   .
   .
   .
   time_point_t another_tp;
   serializer.read(another_tp);

对写入/读取的调用,假设 time_point_t 类型的实例可以以某种方式转换为字节表示形式,然后可以将其写入磁盘或套接字等或从磁盘或套接字等读取。

Alf 建议的一个可能的解决方案如下:

   std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now();

   //Generate POD to write to disk
   unsigned long long ns0 = t0.time_since_epoch().count();

   //Read POD from disk and attempt to instantiate time_point
   std::chrono::high_resolution_clock::duration d(ns0)

   std::chrono::high_resolution_clock::time_point t1(d);

   unsigned long long ns1 = t1.time_since_epoch().count();

   if ((t0 != t1) || (ns0 != ns1))
   {
      std::cout << "Error time points don't match!\n";
   }

注意: 上面的代码有一个错误,因为最终实例化的时间点与原始时间点不匹配。

在旧式 time_t 的情况下,通常只是根据其 sizeof 将整个实体写入磁盘,然后以相同的方式读回 - 简而言之,新的 std::chrono 类型相当于什么?

c++ serialization c++11 persistence c++-chrono
2个回答
25
投票

从磁盘或套接字读取意味着您可能正在未执行写入操作的应用程序实例中进行读取。 在这种情况下,仅序列化持续时间是不够的。

A

time_point
是自未指定纪元以来的
duration
时间量。 纪元可以是任何东西。 在我的计算机上,
std::chrono::high_resolution_clock
的纪元是计算机启动时。 IE。该时钟报告自启动以来的纳秒数。

如果一个应用程序写入 time_since_epoch().count(),计算机重新启动,然后另一个(甚至相同)应用程序将其读回,则读入的值没有任何意义,除非您碰巧以某种方式知道两次启动之间的时间量。

为了可靠地序列化

time_point
,必须安排作者和读者就某个纪元达成一致,然后确保写入和读取的
time_point
是相对于该纪元的。 例如,人们可能会安排使用 POSIX 纪元:New Years 1970 UTC。

事实证明,我所知道的每个

std::chrono::system_clock
实现都使用 Unix 时间,这是从 1970 年新年开始测量的 UTC 的近似值。但是我知道
std::chrono::high_resolution_clock
没有共同的纪元。

只有当您能够以某种方式确保读取器和写入器时钟在共同纪元上达成一致时,您才能将 time_point 序列化为持续时间。

C++20 更新

std::chrono::system_clock
的纪元现在指定Unix时间(1970-01-01 00:00:00 UTC,忽略闰秒)。


8
投票

time_point
构造函数接受一个
duration
,您可以从成员
duration
获得一个
time_since_epoch
。因此,问题减少为序列化
duration
值。并且
duration
有一个接受多个刻度的构造函数,以及一个生成刻度数的成员函数
count

这一切只是通过谷歌搜索

std::chrono::time_point
并查看谷歌给我找到的cppreference文档。

阅读文档通常是个好主意。


附录:一个例子。

#include <chrono>
#include <iostream>
#include <typeinfo>
using namespace std;

auto main() -> int
{
    using Clock = chrono::high_resolution_clock;
    using Time_point = Clock::time_point;
    using Duration = Clock::duration;

    Time_point const t0 = Clock::now();

    //Generate POD to write to disk
    Duration::rep const ns0 = t0.time_since_epoch().count();

    //Read POD from disk and attempt to instantiate time_point
    Duration const d(ns0);
    Time_point const t1(d);

    cout << "Basic number type is " << typeid( ns0 ).name() << "." << endl;
    if( t0 != t1 )
    {
        cout << "Error time points don't match!" << endl;
    }
    else
    {
        cout << "Reconstituted time is OK." << endl;
    }
}

在 Visual C++ 12.0 中,报告的基本类型是

__int64
,即
long long
,而在 Windows 中的 g++ 4.8.2 中,报告的类型是
x
,这可能意味着相同。

两个编译器的重构时间与原始时间相同。

附录:正如 Dina 在评论中指出的那样,从 C++14 开始,C++ 标准没有指定纪元,因此为了使其跨机器或使用不同的时钟工作,有必要添加额外的步骤,标准化序列化数据的纪元,例如最自然的是Posix 时间,即自 1970 年 1 月 1 日星期四 00:00:00 协调世界时 (UTC) 以来的时间。

© www.soinside.com 2019 - 2024. All rights reserved.