我提供的日期不是在DST(夏令时)期间,但是当tm_isdst设置为1时,mktime通常做的是将tm_isdst更改为0,并相应地调整时间,移动1小时.
然而,在大约1928年至1933年的时间段内(找不到不同的范围),行为是不同的. tm_isdst字段设置为0,但时间不会更改.这在执行时间计算等时会产生奇怪的现象.
我有一个很小的测试程序,对于给定的输入日期打印:原始struct tm,在调用mktime之后的struct tm,mktime结果和struct 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()中的一个bug给我,但也许我错过了一些东西.
测试测试程序如下,也可用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,sizeof(tm)); memset(&tm2,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,1); test(2013,1); test(1927,1); test(1929,1); test(1932,1); test(1934,1); return 0; }
/* tm.tm_isdst has the wrong value. Look for a neighboring time with the right value,and use its UTC offset. Heuristic: probe the adjacent timestamps in both directions,looking for the desired isdst. This should work for all real time zone histories in the tz database. */ /* Distance between probes when looking for a DST boundary. In tzdata2003a,the shortest period of DST is 601200 seconds (e.g.,America/Recife starting 2000-10-08 01:00),and the shortest period of non-DST surrounded by DST is 694800 seconds (Africa/Tunis starting 1943-04-17 01:00). Use the minimum of these two values,so we don't miss these short periods when probing. */ int stride = 601200; /* The longest period of DST in tzdata2003a is 536454000 seconds (e.g.,America/Jujuy starting 1946-10-01 01:00). The longest period of non-DST is much longer,but it makes no real sense to search for more than a year of non-DST,so use the DST max. */ int duration_max = 536454000; /* Search in both directions,so the maximum distance is half the duration; add the stride to avoid off-by-1 problems. */ int delta_bound = duration_max / 2 + stride;
如果你做数学运算,你会发现delta_bound是268828200秒,相当于大约8年半.这几乎完全是zdump日期(1919年和1942年)与神秘转换时期(1928年和1933年)之间的差异.每个人都在25小时30分钟之内休息.我没有更深入地找到这个神奇数字的原因.
在不理解整个事情的情况下,我认为评论基本上意味着当你处于从1919年到1942年的那个长期非DST延伸的中间部分时,该算法试图在你提供的那个附近找到一个有效的dst = 1时间戳.错误的dst = 1,并在找到之前放弃,因为它没有任何意义.在中间部分之外的年份也可能没有多大意义,但作为与Jujuy相关的调整参数的副作用表现不同.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。