令人困惑的mktime()函数行为:将tm_hour计数增加1

时间:2012-08-25 12:45:18

标签: c++ dst mktime

我在代码下面执行。

int main()
{
struct tm storage={0,0,0,0,0,0,0,0,0};
char *p = NULL; 
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage);
char buff[1024]={0};
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
storage.tm_sec += 20;
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
mktime(&storage);
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
return 0;
}

如果以上程序执行,则打印'2012-08-25 13:23:32'而不是'2012-08-25 12:23:32'。请帮助,为什么它增加了tm_hour值。 如果我在程序中输入日期为“2012-02-25 12:23:32”,这可以正常工作,这很令人困惑。

OUtput - &gt;

[user@rtpkvm55-vm2 root]$ ./a.out
2012-08-25 12:23:12
2012-08-25 12:23:32
2012-08-25 13:23:32
[user@rtpkvm55-vm2 root]$

我系统上的日期信息, - &gt;

[user@rtpkvm55-vm2 root]$ date
Sat Aug 25 08:28:26 EDT 2012

3 个答案:

答案 0 :(得分:15)

会发生什么

您指定的日期有夏令时生效,但在调用mktime时,storage.tm_isdst为零。 mktime看到了这一点,并认为“嘿,他们给了我一个日期不正确的夏令时标志,让我们解决它”。然后,它将tm_isdst设置为1并更改tm_hour

另见this答案。

修复

  • 使用timegm代替mktime
  • 在调用mktime之前将时区设置为UTC(另请参阅timegm中的示例):
    setenv("TZ", "", 1);
    tzset();
    mktime();
  • 使用一个好的日期时间库(例如boost::locale::date_time / boost::date_time,但在选择一个之前阅读boost::locale::date_time页面上的问答部分)

答案 1 :(得分:4)

哇,没有办法绕过它。它必须是系统执行mktime(3)中的错误。 mktime(3)不应该改变传递给它的struct tm *

我建议检查storage.tm_isdst的值。尝试将其设置为0以确保它不会与DST混淆。如果这不起作用,请尝试将其设置为-1以使其自动确定正确的值。

mktime - convert broken-down time into time since the Epoch

  

tm_isdst的正值或0值会导致mktime()最初假设夏令时分别在指定时间内有效或无效。 tm_isdst的负值会导致mktime()尝试确定夏令时是否在指定时间内有效。


我错误的是mktime(3)没有修改struct tm *。标准化值是正确的行为。

答案 2 :(得分:0)

您必须在 tm_isdst 结构中设置 tm 否则它是未初始化的,因此被设置为随机垃圾值。然后,当您根据 mktime 变量中的随机垃圾调用 tm_isdst 时,它要么应用夏令时,要么不应用,似乎不可预测。

但是,如果您将其设置为 -1,您会告诉 mktime 您不知道夏令时是否生效,因此对 mktime 的第一次调用将修复它.

因此,解决此问题的最简单方法是添加:

storage.tm_isdst = -1;

在调用 mktime 之前。