奇怪的mktime()行为

时间:2019-04-29 12:27:17

标签: c dst mktime

为什么mktime()在CET时区将tm.tm_isdst = 1转换为31/03/2019 02:00到01:00?

我认为这是无效的组合。

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void reset(struct tm* tm){
    (*tm) = (const struct tm){0};

    tm->tm_sec = 0;
    tm->tm_min = 1;
    tm->tm_hour = 2;
    tm->tm_mon = 2;
    tm->tm_mday = 31;
    tm->tm_year = 2019 - 1900;
}

int main(int argc, char **argv)
{
    struct tm   tm;
    int secs;

    reset(&tm);
    printf("Before mktime\n");
        printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec);

    tm.tm_isdst = 0;
    secs = mktime(&tm);
                printf("After mktime tm.tm_isdst = 0;\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    reset(&tm);
    tm.tm_isdst = 1;
    secs = mktime(&tm);
    printf("After mktime tm.tm_isdst = 1;\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    reset(&tm);    
    tm.tm_isdst = -1;
    secs = mktime(&tm);
    printf("After mktime tm.tm_isdst = -1\n");
    printf(" %04d-%02d-%02d %02d:%02d:%02d TZ=%s , tm_isdst = %d, timestamp=%i\n", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tm.tm_isdst, secs);

    return 0;
}

输出:

% date
Sun Mar 31 06:50:42 CEST 2019
% test_mktime
Before mktime
 2019-03-31 02:01:00
After mktime tm.tm_isdst = 0;
 2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060
After mktime tm.tm_isdst = 1;
 2019-03-31 01:01:00 TZ=CET , tm_isdst = 0, timestamp=1553990460
After mktime tm.tm_isdst = -1
 2019-03-31 03:01:00 TZ=CEST , tm_isdst = 1, timestamp=1553994060

2 个答案:

答案 0 :(得分:2)

  1. 2019-03-31 02:01:00 CET(is_dst = 0,UTC + 1)不存在,但等同于2019-03-31 01:01:00 UTC(1553994060秒后纪元),相当于CEST 2019-03-31 03:01:00(is_dst = 1,UTC + 2)。
  2. 2019-03-31 02:01:00 CEST(is_dst = 1,UTC + 2)不存在,但等效于UTC 2019-03-31 00:01:00(1553990460秒后纪元),相当于CET 2019-03-31 01:01:00(is_dst = 0,UTC + 1)。 (请注意:1553994060-1553990460 = 3600,相差1小时。)
  3. 对于is_dst = -1,该实现尝试计算夏令时是否有效,但是由于2019-03-31 02:01:00对于CET和CEST均无效,因此它只选择一个或一个其他。在这种情况下,它假定输入时间为标准时间2019-03-31 02:01:00 CET(is_dst = 0,UTC + 1),该时间不存在,但等同于2019-03-31 01:01:00 UTC(时代后的1553994060秒),相当于CEST 2019-03-31 03:01:00(is_dst = 1,UTC + 2)。

答案 1 :(得分:1)

在DST更改CET / CEST区域的时间为2019年3月31日02:00时,该日期的第二小时时间不用于该区域的计时。 mktime被记录为对输入struct tm中的数据进行规范化,并且在这里起作用。

具体地说,

  • 如果根据标准时间解释时间戳2019-03-31 02:01:00,换句话说,将其作为01:01:00之后的一小时,则它对应于2019-03- CEST 31 03:01:00。如您的程序所示,这就是struct tm的规范化方式。返回值对应于该时间。

  • 如果根据夏时制来解释时间戳2019-03-31 02:01:00,换句话说,就是03:01:00之前一小时的时间,则它对应于2019-03 -31 01:01:00 CET。如您的程序所示,这就是struct tm的规范化方式。返回值对应于该时间,并且表示的时间比其他情况下返回的值早3600秒。

  • 如果您指定是否将给定时间解释为DST生效是未知的,则必须mktime进行猜测。对于大多数时间和日期,它将基于该日期和时间的DST是否有效来进行选择,但这在此没有任何答案。在我看来,它实际上是在这里解释夏令时的标准时间,因为这似乎更可能是对提供该输入的程序的期望。