【问题标题】:portable way to store milliseconds with chrono使用chrono存储毫秒的便携方式
【发布时间】:2016-09-29 06:41:59
【问题描述】:

我的代码如下-

int main(){
    ....

    auto time = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);

    ....
    return 0;
}

这里的变量time 使用typeid().name() 方法提供l 的输出,但是可以安全地假设如果我将auto 替换为long 类型,该变量仍将存储不同的正确毫秒数机器?

我需要它,因为我不能将 auto 指定为类成员中的类型,因为它们可能不是 constexpr 或 static 。我的意图是将数据发送到浏览器,在那里我可以做var d = new Date(time),它会显示正确的时间。通信部分已经通过json格式计算出来了,我只是纠结于如何在不同系统之间正确存储。

【问题讨论】:

    标签: c++ date c++11 c++14 chrono


    【解决方案1】:

    [...] 是否可以假设如果我将 auto 替换为 long 类型,该变量仍将在不同机器上存储正确的毫秒数?

    不,您需要至少 45 位的有符号整数类型long 不保证是。你应该使用std::chrono::milliseconds::rep:

    using namespace std::chrono;
    milliseconds::rep time = 
        duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    

    另请注意,就可移植性而言,system_clock 的纪元不能保证为标准的 1970 年 1 月 1 日 00:00:00 UTC(即使大多数时间都是如此)。

    【讨论】:

    • 等等什么? the system_clock's epoch is not guaranteed to be January 1st 1970 00:00:00 UTC by the standard,那我该如何检查呢?我的意思是它是否依赖于编译器及其版本、操作系统或机器架构?
    • @hg_git 您可以使用to_time_tgmtimesystem_clock 获取std::tm 并检查这是否是正确的日期,如果不是,您需要这样做一些额外的计算。纪元取决于系统,而不是编译器,请参阅 [wikipedia[(en.wikipedia.org/wiki/Epoch_%28reference_date%29#Computing)。纪元不太可能与 UNIX 纪元不同,但从标准的角度来看,这并不能保证。
    • 此时,1970-01-01 00:00:00 UTC 是事实上的标准(但未由 C++ 标准指定)。我计划尝试在不久的将来的提案中指定它。另请参阅有关这场勉强避免的灾难的信息:twitter.com/StephanTLavavej/status/780816381394550784
    【解决方案2】:

    现有的两个答案都很好。但只要您使用 C++,我鼓励您将数据成员设为类型:

    std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
    

    我知道这是一个丑陋的嘴,但它可以很容易地变得更漂亮。它也很容易使用。它还有助于防止 C++ 代码中出现运行时错误。

    让它更漂亮

    我推荐这个模板使用:

    template <class Duration>
        using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
    

    现在你可以让你的数据成员有类型:

    sys_time<std::chrono::milliseconds> time_;
    

    这更具可读性,它完全保留了您存储时间点的语义,而不是任意数字或葡萄柚中的卡路里数。

    类型安全

    假设六个月后你重新访问这段代码并且你写了:

    auto z = x.time_ + y.time_;
    

    如果您之前决定将time_ 输入std::int64_tstd::chrono::milliseconds::rep,那么上面的新代码行将编译并产生运行时错误。添加两个时间点。明天+今天是荒谬的。

    但是,如果您之前决定按照我的建议将time_ 输入sys_time&lt;milliseconds&gt;,则上面创建z 的代码行无法编译。 类型系统检测到逻辑错误在编译时。现在你不得不立即重新审视你的逻辑并发现你为什么要尝试添加两个时间点。也许它只是一个类型-o,而您打算减去它们(这是合乎逻辑的,编译并产生milliseconds 类型的duration)。

    易于使用

    您可以使用以下简单语法将now() 分配给您的time_ 数据成员:

    using namespace std::chrono;
    time_ = time_point_cast<milliseconds>(system_clock::now());
    

    现在time_ 只是另一个基于system_clocktime_point,但精度为milliseconds。要输出到 json,您可以通过以下方式获得内部有符号整数值:

    json_stream << time_.time_since_epoch().count();
    

    对于从 json 解析,您可以:

    std::int64_t temp;
    json_stream >> temp;
    time_ = sys_time<milliseconds>{milliseconds{temp}};
    

    【讨论】:

    • 是的,当然,顺便说一句,我是你的忠实粉丝:D 无论如何都会使用你的日期库。
    • @hg_git:太棒了,谢谢。 date::sys_time&lt;D&gt; 在 date.h 中预制。
    • 为什么不将变量键入为 decltype(std::chrono::system_clock::now()) start;
    • OP 表达了以毫秒精度存储的愿望。您的建议将导致其他精度。
    【解决方案3】:

    您的方法可行且可移植,但我建议使用更直接的方法来计算毫秒数:

    std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()
    

    这肯定会起作用,因为 .count() 返回一个 std::chrono::milliseconds::rep,它是“至少 45 位的有符号整数类型”并且应该适合 long。

    注意:不能保证 system_clock 具有毫秒分辨率。但无论如何你都会在几毫秒内得到结果。

    旁注:我可以很好地利用using namespace std::chrono;,因为这会显着减少代码长度。

    【讨论】:

      猜你喜欢
      • 2011-03-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      相关资源
      最近更新 更多