【问题标题】:Alternative to mktime in C++在 C++ 中替代 mktime
【发布时间】:2018-01-09 10:19:20
【问题描述】:
uint64_t  timestamp_nanoseconds  = 634019142119225390;
time_t result = timestamp_nanoseconds / 1000000000;
struct tm * timeinfo = gmtime(&result);
struct tm dateInfo ;
dateInfo.tm_mday = timeinfo->tm_mday ;
dateInfo.tm_mon = timeinfo->tm_mon ;
dateInfo.tm_year = timeinfo->tm_year ;
dateInfo.tm_hour = 0 ;
dateInfo.tm_min = 0 ;
dateInfo.tm_sec = 0 ;
time_t NoOfSecInDate = mktime ( &dateInfo );

从以纳秒为单位的输入时间戳中,我们可以得到日期,如在 dateInfo 结构中设置的代码所示。从那时起,我们需要从输入日期的午夜开始计算经过的时间(以秒为单位)。

我们将输入作为自 1970 年 1 月 1 日以来经过的时间(以纳秒为单位)。例如,634019142119225390。从中我们提取时间设置为 00:00:00 的日期,我们需要找到表示经过的无符号整数的经过时间自 1970 年 1 月 1 日 UTC 时间 00:00 UTC 以来的纳秒时间,从该日期的午夜开始。

解决方案应该针对任何给定的时间戳,而不是针对当前日期。

在上面的代码中,我们发现 mktime 函数需要大约 64 微秒才能完成,这是很多时间并且不是预期的

您是否有任何其他替代 mktime 函数的方法,它可以实现相同的结果,即返回自纪元以来经过的时间(以秒为单位),但时间更短。

【问题讨论】:

  • 我不明白 - 您从 time_t 开始,将其放入 tm,然后使用 mktime 从您开始的信息中获取 time_t?为什么不直接使用您必须开始的result time_t?

标签: c++ low-latency mktime


【解决方案1】:

这可以通过<chrono>Howard Hinnant's free, open-source, date-time library 高效完成。

给定:

uint64_t  timestamp_nanoseconds  = 634019142119225390;

基于system_clocknanoseconds 形成std::chrono::time_point。日期时间库为此类类型提供了模板类型别名,使这变得非常容易:

sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};

接下来,您可以将这个纳秒精度的time_point 截断为days 精度time_point

auto sd = floor<days>(ts);

sd 是一个 system_clock time_point 计算纪元以来的天数(而不是纳秒)。接下来,您可以将sd 转换为year_month_day,这正是它听起来的样子:一个{year, month, day} 结构,每个字段都有getter:

year_month_day ymd = sd;

这个问题的相关部分,这是你从午夜开始得到纳秒的方式:

auto tod = ts - sd;

如果你想要以秒为单位,它

auto tod = duration_cast<seconds>(ts - sd);

总而言之,从 uint64_t 纳秒计数到当天 (UTC) 的秒数,并对其计时,它是:

auto t0 = steady_clock::now();
sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};
auto tod = duration_cast<seconds>(ts - floor<days>(ts));
auto t1 = steady_clock::now();

鉴于 634019142119225390 的输入,并在 macOS 的 -O3 处使用 clang 进行编译,结果如下:

tod == 15942s

大约需要 200ns。

由于使用了floor&lt;days&gt;,而不是duration_cast&lt;days&gt;,这个公式对于正和负输入都适用。例如,-1'000'000'000 的输入给出了86399s 的时间。

【讨论】:

    【解决方案2】:

    您正试图获取同一 UTC 日期开始时的时间。为此,您可以在几秒钟内完成计算:

    struct timezone tz = {0, 0};
    struct timeval start, end;
    
    gettimeofday(&start, &tz);
    uint64_t  timestamp_nanoseconds  = 634019142119225390ULL;
    time_t result = timestamp_nanoseconds / 1000000000ULL;
    time_t day = result - (result % 86400);
    gettimeofday(&end, &tz);
    
    struct timeval dsec;
    timersub(&end, &start, &dsec);
    printf("calc took %ld sec %ld usec.\n",
       dsec.tv_sec, dsec.tv_usec, s);
    
    printf("UTC: %s",asctime(gmtime(&now)));
    printf("Day: %s",asctime(gmtime(&day)));
    

    这需要更少的时间:

    calc took 0 sec 1 usec.  total 0.000000
    UTC: Sat Feb  3 04:25:42 1990
    Day: Sat Feb  3 00:00:00 1990
    

    如果您想在当地时区获得一天的开始,您可以在 day 的计算中添加一个偏移量。

    【讨论】:

    • 从以纳秒为单位的输入时间戳,我们可以得到日期,如在 dateInfo 结构中设置的代码所示。从那时起,我们需要找到从输入日期的午夜开始经过的时间(以秒为单位),而不是当前日期。
    • 已修改以显示示例数据的计算。
    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2021-09-29
    • 2015-02-05
    相关资源
    最近更新 更多