【问题标题】:Confusing behaviour of mktime() function : increasing tm_hour count by onemktime() 函数的令人困惑的行为:将 tm_hour 计数加一
【发布时间】:2012-08-20 18:23:56
【问题描述】:

我正在执行下面的代码。

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”,这会正常工作,这很令人困惑。

输出 ->

[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]$

我系统上的日期信息,-->

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

【问题讨论】:

  • 代码没有显示小时在增加。为此,请显示来自strptime 的结果以及来自对mktime 的调用的结果。这将有助于确定实际发生的情况。
  • 抱歉,我无法解析。它有三个输出而不是一个,但没有说明它们来自哪里。请更新示例代码以匹配输出。

标签: c++ dst mktime


【解决方案1】:

会发生什么

您指定的日期有夏令时,但在调用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 页面上的问答部分)

【讨论】:

  • 谢谢,它帮助并解释了我的疑问。现在我需要在两种类型的系统(DST 开和关)上运行我的一段代码。例如如果我在调用 mktime() 之前将 tm_isdst = 1 放入代码中,它将在 DST 关闭的系统上给出不正确的结果(它最终会将 tm_hour 减一)。有没有其他方法可以将秒数添加到给定日期? (可能是“避免使用 mktime()”或“巧妙地使用 mktime(),这将忽略 tm_isdst 标志”)
  • @DhirajNeve:我添加了一些修复。如果你需要做更多与日期/时间相关的事情,我认为你应该使用一个好的 C++ 日期/时间库。
  • 不是只有timegm POSIX 吗?
  • @stackptr timegm 是 GNU 扩展,不在 POSIX 中。我认为在 Windows 上你有 _mkgmtime 如果我没记错的话,它会做同样的事情。
【解决方案2】:

哇,没有办法绕过它。它一定是您系统的 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 *。将值标准化是正确的行为。

【讨论】:

  • 根据man mktime (linux.die.net/man/3/mktime) 它可以(并且确实)改变stuct tm。它标准化其值并填充缺失的字段。
  • @rve 看起来你是对的。我误解了措辞。我认为这是为了设置 time_t 的目的而正常化。
【解决方案3】:

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

但是,如果您将其设置为 -1,您会告诉 mktime 您不知道夏令时是否有效,因此第一次调用 mktime 将解决此问题。

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

storage.tm_isdst = -1;

在致电mktime之前。

【讨论】:

    猜你喜欢
    • 2011-11-18
    • 2014-02-04
    • 2014-10-17
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    相关资源
    最近更新 更多