【问题标题】:fully separated date with milliseconds from std::chrono::system_clock与 std::chrono::system_clock 完全分开的日期,以毫秒为单位
【发布时间】:2013-06-30 03:16:06
【问题描述】:

我当前的模式(对于 unix)是调用gettimeofday,将tv_sec 字段转换为time_t,将其传递给localtime,然后将结果与tv_usec 结合起来。这给了我一个完整的日期(年、月、日、小时、分钟、秒、纳秒)。

我正在尝试将我的代码更新为 C++11,以实现可移植性和一般的良好实践。我能够做到以下几点:

auto currentTime = std::chrono::system_clock::now( );
const time_t time = std::chrono::system_clock::to_time_t( currentTime );
const tm *values = localtime( &time );
// read values->tm_year, etc.

但我被困在毫秒/纳秒上。一方面,to_time_t 声称舍入是实现定义的(!)所以我不知道 22.6 秒的最终读数是否实际上应该是 21.6,另一方面我不知道如何得到毫秒数前一秒(标准保证秒数是正常的吗?即我可以得到自纪元以来的总毫秒数并对其取模吗?即使这样也感觉很丑)。

我应该如何以毫秒为单位从std::chrono::system_clock 获取当前日期?

【问题讨论】:

  • 如果 std::time_t 的精度较低,则由实现定义该值是舍入还是截断 无论哪种情况,22.6 都不会是 21.6,所以不用担心。
  • @TomKnapen 但是 21.6 可以变成 22.6,如果它被舍入而不是截断秒。也许我的措辞不是最好的,但这就是我的意思。
  • 根据我的经验,将 21.6 舍入等于 22,将 21.6 截断等于 21。因此,无论哪种方式,除非您自己添加“小数”部分,否则 21.6 不可能变成 22.6。
  • @TomKnapen 但关键是我自己am添加了小数部分;我将从(舍入或截断的)time_t 值中获取秒数,并从原始时钟中获取小数部分。

标签: c++ c++11 time chrono


【解决方案1】:

我意识到我可以使用from_time_t 来获取“舍入”值,并检查发生了哪种类型的舍入。这也不依赖于每秒正好是 1000 毫秒,并且适用于开箱即用的 C++11:

const auto currentTime = std::chrono::system_clock::now( );
time_t time = std::chrono::system_clock::to_time_t( currentTime );
auto currentTimeRounded = std::chrono::system_clock::from_time_t( time );
if( currentTimeRounded > currentTime ) {
    -- time;
    currentTimeRounded -= std::chrono::seconds( 1 );
}
const tm *values = localtime( &time );
int year = values->tm_year + 1900;
// etc.
int milliseconds = std::chrono::duration_cast<std::chrono::duration<int,std::milli> >( currentTime - currentTimeRounded ).count( );

【讨论】:

    【解决方案2】:

    使用这个free, open-source library,您可以获得毫秒精度的本地时间,如下所示:

    #include "tz.h"
    #include <iostream>
    
    int
    main()
    {
        using namespace date;
        using namespace std::chrono;
        std::cout << make_zoned(current_zone(),
                                floor<milliseconds>(system_clock::now())) << '\n';
    }
    

    这只是为我输出:

    2016-09-06 12:35:09.102 EDT
    

    make_zoned 是一个创建zoned_time&lt;milliseconds&gt; 的工厂函数。工厂函数为您推断出所需的精度。 zoned_timetime_zonelocal_time 的配对。您可以通过以下方式获取本地时间:

    local_time<milliseconds> lt = zt.get_local_time();
    

    local_time 是一个chrono::time_point。如果您愿意,可以将其分解为日期和时间字段类型:

    auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
    auto lt = zt.get_local_time();
    local_days ld = floor<days>(lt);          // local time truncated to days
    year_month_day ymd{ld};                   // {year, month, day}
    time_of_day<milliseconds> time{lt - ld};  // {hours, minutes, seconds, milliseconds}
    // auto time = make_time(lt - ld);        // another way to create time_of_day
    auto y = ymd.year();         // 2016_y
    auto m = ymd.month();        // sep
    auto d = ymd.day();          // 6_d
    auto h = time.hours();       // 12h
    auto min = time.minutes();   // 35min
    auto s = time.seconds();     // 9s
    auto ms = time.subseconds(); // 102ms
    

    【讨论】:

      【解决方案3】:

      您可以这样做,而不是使用 to_time_t 来进行四舍五入

      auto tp = std::system_clock::now();
      auto s = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
      auto t = (time_t)(s.count());
      

      这样您就可以在没有四舍五入的情况下获得秒数。这比检查to_time_tfrom_time_t 之间的差异更有效。

      【讨论】:

        【解决方案4】:

        我是这样阅读标准的:

        值是舍入还是截断由实现定义,但自然舍入或截断只发生在结果 time_t 的最详细部分。也就是说:你从 time_t 获得的组合信息永远不会超过其粒度的 0.5。

        如果您的系统上的 time_t 仅支持秒,那么可能存在 0.5 秒的系统不确定性是正确的(除非您了解事情是如何实现的)。

        tv_usec 不是标准 C++,而是 posix 上 time_t 的访问器。总而言之,您不应期望任何舍入效果大于系统支持的最小时间值差的一半,因此肯定不超过 0.5 微秒。

        最直接的方法是使用 boost ptime。它有fractional_seconds()等方法 http://www.boost.org/doc/libs/1_53_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class

        对于与std::chrono 的互操作,您可以按照此处所述进行转换:https://stackoverflow.com/a/4918873/1149664

        或者,看看这个问题:How to convert std::chrono::time_point to calendar datetime string with fractional seconds?

        【讨论】:

        • 我实际上是直接从gettimeofday 的结构中获取tv_usec 值,然后再通过time_t,我认为这是安全的。我认为time_t 只保留秒数,所以我期待 0.5 秒的差异而不是 0.5 微秒,尽管我没有测试(不确定我可以,因为它是实现定义的)。至于提升答案;我得花点时间了解它在做什么,但我会尽可能避免提升,只坚持那些成为标准的东西。
        • 好的,我知道它在做什么;您将时间写入流并将其读回以有效地“地板”它,然后得到差异。我可以看到逻辑,但它似乎非常复杂。将数字转换为字符串/从字符串转换只是为了比较它们是我一直避免的。必须有一种方法可以在不操作字符串/流的情况下做到这一点……
        • 不,这不是重点,也不是我的意思。流只是为了显示结果,你把你输入的东西拿回来。你到底想对时间做什么?无论哪种情况,提升时间库都是查看的地方。
        • 那我误会了;我想写类似“HH:MM:SS.xxxx”的东西。似乎您代码中的“差异”会给我“.xxxx”位,但是您写入流然后从它读取以获取该变量。
        猜你喜欢
        • 2017-09-02
        • 2014-03-23
        • 1970-01-01
        • 2018-01-03
        • 1970-01-01
        • 2019-05-04
        • 2023-02-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多