【发布时间】:2013-12-23 05:04:18
【问题描述】:
我一直在玩 mktime,我注意到一种奇怪且不一致的行为。
我为它提供了一个不在 DST(夏令时)期间的日期,但将 tm_isdst 设置为 1,mktime 通常所做的是将 tm_isdst 更改为 0,并相应地调整时间,偏移 1 小时。
但是,在大约 1928..1933 年的时间段内(找不到不同的范围),行为是不同的。 tm_isdst 字段设置为 0,但时间不变。这会在执行时间计算等时导致奇怪。
我有一个很小的测试程序,它对于给定的输入日期打印:原始结构 tm,在其上调用 mktime 后的结构 tm,mktime 结果和结构 tm,它是在 mktime 结果上调用 localtime 的结果(应该代表与原始时刻相同的时刻)。
输出是:
2013-01-01 12:00:00 (off=0, dst=1) -> 2013-01-01 11:00:00 (off=-28800, dst=0) -> 1357066800 -> 2013-01-01 11:00:00 (off=-28800, dst=0)
1927-01-01 12:00:00 (off=0, dst=1) -> 1927-01-01 11:00:00 (off=-28800, dst=0) -> -1356930000 -> 1927-01-01 11:00:00 (off=-28800, dst=0)
1929-01-01 12:00:00 (off=0, dst=1) -> 1929-01-01 12:00:00 (off=-28800, dst=0) -> -1293768000 -> 1929-01-01 12:00:00 (off=-28800, dst=0)
1932-01-01 12:00:00 (off=0, dst=1) -> 1932-01-01 12:00:00 (off=-28800, dst=0) -> -1199160000 -> 1932-01-01 12:00:00 (off=-28800, dst=0)
1934-01-01 12:00:00 (off=0, dst=1) -> 1934-01-01 11:00:00 (off=-28800, dst=0) -> -1136005200 -> 1934-01-01 11:00:00 (off=-28800, dst=0)
请注意,对于 2013、1927、1934 年,小时已更改且 dst 设置为 0。但在 1929 年和 1932 年,小时未更改,但 dst 是。
超级奇怪的是,在 tzinfo 中没有关于那个时间范围的信息 - 洛杉矶的 zdump 显示最接近的变化是在 1919 年和 1942 年。
这是在 CentOS 上,内核 2.6.32-358.11.1.el6.x86_64,glibc-2.12-1.107.el6.x86_64。
在 MacOSX 上,进一步调查似乎(始终如一)按预期工作。所以这对我来说看起来像是 mktime() 中的一个错误,但也许我遗漏了一些东西。
测试测试程序如下,也可here
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* printtm(struct tm tm)
{
static char buf[100];
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d (off=%ld, dst=%d)",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_gmtoff, tm.tm_isdst);
return buf;
}
void test(int y, int m, int d, int hh, int mm, int ss, int isdst)
{
// Prepare tm structs
struct tm tm, tm2;
memset(&tm, 0, sizeof(tm));
memset(&tm2, 0, sizeof(tm));
tm.tm_year = y - 1900;
tm.tm_mon = m - 1;
tm.tm_mday = d;
tm.tm_hour = hh;
tm.tm_min = mm;
tm.tm_sec = ss;
tm.tm_isdst = isdst;
// Convert tm -> t -> tm and print
printf("%s -> ", printtm(tm));
time_t t = mktime(&tm);
printf("%s -> ", printtm(tm));
printf("%12ld -> ", t);
localtime_r(&t, &tm2);
printf("%s\n", printtm(tm));
}
int main()
{
setenv("TZ", ":America/Los_Angeles", 1);
tzset();
test(2013,07,01, 12,0,0, 1);
test(2013,01,01, 12,0,0, 1);
test(1927,01,01, 12,0,0, 1);
test(1929,01,01, 12,0,0, 1);
test(1932,01,01, 12,0,0, 1);
test(1934,01,01, 12,0,0, 1);
return 0;
}
【问题讨论】:
-
了解您正在使用的操作系统以及
time_t是 32 位还是 64 位(即使您似乎仍在 32 位范围内安全地工作)会很有用。 -
不要责怪图书馆或你自己...找一个硬件人来责备。大声笑
-
添加平台信息:CentOS,内核 2.6.32-358.11.1.el6.x86_64,glibc-2.12-1.107.el6.x86_64。
-
嗯...我也在 MacOSX 上测试过...行为一致...所以要么是 glibc 差异,要么是时区信息差异。