奇怪的mktime逻辑与负秒

我一直在使用mktime / localtime进行时间管理,包括对日期/时间的一些重要算术。

当向mktime提供包含负值的struct tm时,我注意到一些非常奇怪的东西。

请参考下面的代码。 在2013年11月3日,洛杉矶有一个DST更改。如果我指定时间为2013-11-04午夜时间并减去24小时,我得到的值与2013-11-03午夜相同。 它与UTC相差25小时,这很好,因为isdst = -1可以说我们正在看’挂钟时间’。 如果我减去1440分钟(24 * 60)则相同。 但是,如果我减去86400(24 * 60 * 60)秒,我得到2013-11-03凌晨1点。 这是UTC方式的24小时差异。 这是以下代码的输出:

2013-11-03 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 2013-12--27 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 2013-11-04 -24:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 2013-11-04 00:-1440:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000 2013-11-04 00:00:-86400 (gmtoff=0, isdst=-1) -> 2013-11-03 01:00:00 (gmtoff=-25200, isdst=1) -> 1383465600 

对我来说这没有意义 – 为什么秒的处理方式与分钟,小时和天数不同? 我看着男人和C标准但找不到任何东西。

这种行为打破了我的一些假设并使事情复杂化。 有人知道mktime / localtime的一个很好的替代品(我测试过boost,ICU和tzcode,对于我需要的东西来说太慢了)。

提前感谢任何想法:)

 #include  #include  #include  #include  char* printtm(struct tm tm) { static char buf[100]; sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d (gmtoff=%ld, isdst=%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) { struct tm tm; memset(&tm, 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; printf("%s -> ", printtm(tm)); time_t t = mktime(&tm); printf("%s -> %ld\n", printtm(tm), t); } int main() { setenv("TZ", ":America/Los_Angeles", 1); tzset(); test(2013,11,03, 0,0,0, -1); test(2013,12,-27, 0,0,0, -1); test(2013,11,04, -24,0,0, -1); test(2013,11,04, 0,-1440,0, -1); test(2013,11,04, 0,0,-86400, -1); return 0; } 

struct tmtm_isdst==-1使用具有超出范围值的mktime是有问题的并且指定不足。 就个人而言,我认为你的系统在这里表现的方式是错误的 ,但标准并不清楚它应该如何表现,因此任何这样的使用都是不可移植的。 要对struct tm进行算术运算,你应该确保tm_isdst预先设置为0或1,这样结果就是明确的。

请注意,执行此操作的一种简单方法是在应用算法确定日光时间是否有效(即填写tm_isdst的确定值)之前,在原始struct tm上调用mktime (使用tm_isdst==-1 )在进行算术调整后再次调用它。