奇怪的 mktime() 行为
Strange mktime() behaviour
为什么 mktime() 将 31/03/2019 02:00 转换为 01:00,tm.tm_isdst = 1,CET 时区?
我认为这是一个无效的组合。
#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
- 2019-03-31 02:01:00 CET (
is_dst = 0
, UTC+1) 不存在,但相当于 2019-03-31 01:01:00 UTC (1553994060 秒在纪元之后),相当于 2019-03-31 03:01:00 CEST (is_dst = 1
, UTC+2).
- 2019-03-31 02:01:00 CEST (
is_dst = 1
, UTC+2) 不存在,但相当于 2019-03-31 00:01:00 UTC(1553990460 秒在纪元之后),相当于 2019-03-31 01:01:00 CET (is_dst = 0
, UTC+1)。 (注:1553994060 - 1553990460 = 3600,相差1小时。)
- 对于
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秒),相当于2019-03-31 03:01:00 CEST (is_dst = 1
, UTC+2).
由于02:00,2019 年 3 月 31 日是 DST 更改 CET / CEST 区域的时间,该日期的第 2 小时的时间不用于该区域的计时。 mktime
被记录为规范化输入中的数据 struct tm
,这在这里发挥作用。
具体来说,
如果时间戳2019-03-3102:01:00按标准时间解释,即01:01:00后一小时的时间,则对应2019-03-31 03:01:00 中欧夏令时。正如您的程序所示,这就是 struct tm
的标准化方式。 return值对应那个时间。
如果时间戳2019-03-3102:01:00按照夏令时来解释,换句话说就是03:01:00前一小时的时间,那么对应到 2019-03-31 01:01:00 CET。正如您的程序所示,这就是 struct tm
的标准化方式。 return 值对应于那个时间,并且表示比 return 在另一种情况下的值早 3600 秒的时间。
如果您指定未知是否将给定时间解释为夏令时有效,则 mktime
必须猜测。对于大多数时间和日期,它会根据 DST 是否对该日期和时间有效来进行选择,但这不会在此处产生任何答案。在我看来,它实际上在这里解释标准时间而不是夏令时似乎是合理的,因为这似乎更可能是提供该输入的程序的期望。
为什么 mktime() 将 31/03/2019 02:00 转换为 01:00,tm.tm_isdst = 1,CET 时区?
我认为这是一个无效的组合。
#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
- 2019-03-31 02:01:00 CET (
is_dst = 0
, UTC+1) 不存在,但相当于 2019-03-31 01:01:00 UTC (1553994060 秒在纪元之后),相当于 2019-03-31 03:01:00 CEST (is_dst = 1
, UTC+2). - 2019-03-31 02:01:00 CEST (
is_dst = 1
, UTC+2) 不存在,但相当于 2019-03-31 00:01:00 UTC(1553990460 秒在纪元之后),相当于 2019-03-31 01:01:00 CET (is_dst = 0
, UTC+1)。 (注:1553994060 - 1553990460 = 3600,相差1小时。) - 对于
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秒),相当于2019-03-31 03:01:00 CEST (is_dst = 1
, UTC+2).
由于02:00,2019 年 3 月 31 日是 DST 更改 CET / CEST 区域的时间,该日期的第 2 小时的时间不用于该区域的计时。 mktime
被记录为规范化输入中的数据 struct tm
,这在这里发挥作用。
具体来说,
如果时间戳2019-03-3102:01:00按标准时间解释,即01:01:00后一小时的时间,则对应2019-03-31 03:01:00 中欧夏令时。正如您的程序所示,这就是
struct tm
的标准化方式。 return值对应那个时间。如果时间戳2019-03-3102:01:00按照夏令时来解释,换句话说就是03:01:00前一小时的时间,那么对应到 2019-03-31 01:01:00 CET。正如您的程序所示,这就是
struct tm
的标准化方式。 return 值对应于那个时间,并且表示比 return 在另一种情况下的值早 3600 秒的时间。如果您指定未知是否将给定时间解释为夏令时有效,则
mktime
必须猜测。对于大多数时间和日期,它会根据 DST 是否对该日期和时间有效来进行选择,但这不会在此处产生任何答案。在我看来,它实际上在这里解释标准时间而不是夏令时似乎是合理的,因为这似乎更可能是提供该输入的程序的期望。