【问题标题】:mktime() gives different results than Howard Hinnant's date library (std::chrono based)mktime() 给出的结果与 Howard Hinnant 的日期库不同(基于 std::chrono)
【发布时间】:2017-03-25 15:08:32
【问题描述】:

我正在使用 Howard Hinnant 的 date C++ 库 (https://howardhinnant.github.io/date/date.html),但我在使用它时有些困惑。下面是一个程序,我使用这个库打印 2017 年 11 月的第三个星期五的年月日。date::year_month_weekday 类与 date::sys_days() 一起使用时,显示正确的日期(2017 年 11 月 17 日),但是当我使用std::chrono::system_clock::to_time_t 将其转换为struct tm 时,存储在此tm 中的结果变为2017 年11 月16 日。我测试了其他情况,似乎struct tmdate::year_month_weekday 转换为总是落后一天。我错过了我的程序中的某些内容吗?程序如下,编译需要C++ 11。

#include <iostream>
#include <chrono>
#include <sys/time.h>
#include "date.h"

using namespace std; 
using namespace std::chrono; 
using namespace date;

int main(int argc, char *argv[]) {  
    date::year y(2017);
    date::month m(11);
    date::weekday wd((unsigned)5);
    date::weekday_indexed wi(wd,3);
    date::year_month_weekday dmwd(y, m, wi);
    std::cout <<  date::sys_days(dmwd) << std::endl; //prints 2017-11-17, which is the 3rd Friday of Nov 2017

    time_t tt = std::chrono::system_clock::to_time_t(date::sys_days(dmwd));        
    struct tm tm1;
    localtime_r(&tt, &tm1);
    std::cout << "tm1.tm_year = " << tm1.tm_year << std::endl;
    std::cout << "tm1.tm_mon = " << tm1.tm_mon << std::endl;
    std::cout << "tm1.tm_mday = " << tm1.tm_mday << std::endl;  //prints 16 instead of 17, one day behind. tm.mday is from 1 to 31.

    return 0; 
}

这个程序的输出如下

2017-11-17
tm1.tm_year = 117  <-- 117+1900=2017
tm1.tm_mon = 10    <-- tm_mon starts form 0, so 10 means November
tm1.tm_mday = 16  <-- tm_mday starts from 1, so 16 is the 16-th day in a month

【问题讨论】:

  • 你试过用gmtime_r()代替localtime_r()吗?
  • 是的,我刚试过,gmtime_r 确实给出了一致的结果,谢谢提示。由于date::year_month_weekday 不包含时间(小时和分钟)信息,我想知道日期库在转换为struct tm 时如何处理它。我还打印了从date::year_month_weekday 转换而来的struct tmtm_hourtm_min。对于所有情况,似乎 tm_hour == 18tm_min == 0 - 可能是因为我在 UTC-6 时区?
  • Fwiw,这里是创建dmwd的替代语法:auto dmwd = fri[3]/nov/2017;

标签: c++ date chrono mktime


【解决方案1】:

Howard Hinnant's date.h 跟踪 Unix Time,在大多数实际用途中是 UTC。同样GitHub repository还有timezone library,如果您需要处理您的本地时间或UTC以外的任何时区。

所以是的,正如 Freddie Chopin 在 cmets 中指出的那样,您会看到 localtime_r 将您计算机的本地时区考虑在内的效果。

您可以根据需要将一天中的任何时间添加到sys_dayssys_daysstd::chrono::time_point,但具有 days 精度。所以一旦你有了sys_days,你现在实际上是在&lt;chrono&gt; 库中,而不是日期库:

system_clock::time_point t = date::sys_days(dmwd) + 6h + 53min + 4s + 123us:

【讨论】:

  • 非常感谢您的解释。又一个问题,我尝试将sys_days(dmwd)改成local_days(dmwd),但是编译不出来,说是没有匹配功能。使用local_days的正确方法是什么?我是否也应该将时区库添加到我的程序中?再次感谢!
  • @WorkOnly:我刚刚尝试了那个实验,它为我编译。哪个编译器/版本?您可以在某个地方设置一个演示,例如:wandbox.org 吗?这是一个沙盒开始:wandbox.org/permlink/HMMMIqtuG6Ia1AHY
  • 我可以毫无问题地编译原始帖子中的程序,但是当我将sys_days(dmwd) 替换为local_days(dmwd) 时,它会给出以下错误消息(Ubuntu 16.04 上的gcc 5.4,带有g++ -std=c++11 date_time.cpp) :date_time.cpp: In function ‘int main(int, char**)’: date_time.cpp:18:73: error: no matching function for call to ‘std::chrono::_V2::system_clock::to_time_t(date::local_days)’ time_t tt = std::chrono::system_clock::to_time_t(date::local_days(dmwd)); ^ In file included from date_time.cpp:2:0:
  • (续)/usr/include/c++/5/chrono:734:7: note: candidate: static time_t std::chrono::_V2::system_clock::to_time_t(const time_point&amp;) to_time_t(const time_point&amp; __t) noexcept ^ /usr/include/c++/5/chrono:734:7: note: no known conversion for argument 1 from ‘date::local_days {aka std::chrono::time_point&lt;date::local_t, std::chrono::duration&lt;int, std::ratio&lt;86400l, 1l&gt; &gt; &gt;}’ to ‘const time_point&amp; {aka const std::chrono::time_point&lt;std::chrono::_V2::system_clock, std::chrono::duration&lt;long int, std::ratio&lt;1l, 1000000000l&gt; &gt; &gt;&amp;}’
  • @WorkOnly:好的,这是有道理的。 system_clock::to_time_tsystem_clock::time_point 作为参数。 sys_days 是粗略的 system_clock::time_point 的 typedef,并隐式转换为 system_clock::time_point。而local_dayschrono::time_point,与system_clock 没有任何关系。编译时错误可防止您意外混淆time_points 的这两个系列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多