mktime()函数的混淆行为:将tm_hour计数增加一



我正在执行以下代码。

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-2512:23:32"。请帮助,为什么它正在增加tm_hour值。如果我在程序中输入日期为"2012-02-25 12:23:32",这是正确的,这很令人困惑。

OUtput->

[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

发生了什么

您指定的日期具有夏令时,但当调用mktime时,storage.tm_isdst为零。mktime看到了这一点,并认为"嘿,他们给了我一个带有错误夏令时标志的日期,让我们纠正它"。然后,它将tm_isdst设置为1并改变tm_hour

另请参阅此答案。

修复

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

哇,这是没有办法的。这一定是你的系统实现mktime(3)中的一个错误。mktime(3)不应更改传递给它的struct tm *

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

mktime-将故障时间转换为Epoch 以来的时间

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


我错了mktime(3)没有修改struct tm *。规范化值是正确的行为。

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

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

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

storage.tm_isdst = -1;

在调用CCD_ 21之前。

这里有一个修复代码的技巧:

int main()
{
    // Need to know if daylight saving is on or off, use the following trick
    // Get the current time in seconds since epoch, convert it to local time,
    // tm_isdst(is daylight saving) value, in the tm variable returned by the localtime(), will be set accordingly
    time_t now = time(0);
    struct tm *tm2= localtime(&now); 
    
    struct tm storage={0,0,0,0,0,0,0,0,tm2->tm_isdst}; // Note: used the is daylight saving on flag fetched above
    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;
}

最新更新