【发布时间】:2013-12-04 22:51:56
【问题描述】:
我一直在使用 mktime/localtime 进行时间管理,包括一些关于日期/时间的繁重算术。
在向 mktime 提供一个包含负值的 struct tm 时,我注意到一些非常奇怪的事情。
获取下面的代码。 2013 年 11 月 3 日洛杉矶发生了 DST 变化。如果我将 tm 中的时间指定为 2013 年 11 月 4 日午夜并减去 24 小时,我得到的值与 2013 年 11 月 3 日午夜相同。 UTC 时间相差 25 小时,这很好,就像 isdst=-1 一样,可以说我们正在查看“挂钟时间”。如果我减去 1440 分钟(24*60),则相同。但是,如果我减去 86400 (24*60*60) 秒,我会得到 2013-11-03 1am。这是 24 小时的 UTC 时差。这是下面代码的输出:
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
对我来说这没有意义 - 为什么秒与分钟、小时和天的处理方式不同?我查看了 man 和 C 标准,但找不到任何东西。
这种行为打破了我的一些假设并使事情复杂化。有人知道 mktime/localtime 的一个很好的替代方案吗(我测试了 boost、ICU 和 tzcode,对于我需要的东西来说都太慢了)。
提前感谢您的任何想法:)
#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 (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;
}
【问题讨论】:
-
@hobbs:是的,确实如此。 C11 7.27.2.3,描述
mktime函数:“结构的tm_wday和tm_yday组件的原始值被忽略,原始值被忽略其他成分不限于上述范围。” (而你刚刚删除了我正在回复的评论。) -
谢谢基思。首先,我没有删除任何cmets,不知道发生了什么。无论如何,我知道 wday/yday,但你的回答并没有说明为什么秒在这里的处理方式与分钟不同。
-
一个名叫“hobbs”的人发表了评论,然后在我写回复时将其删除。我留下了我的回复,因为它似乎仍然相关。你是对的,我没有说明为什么秒数会被区别对待——这就是我发表评论而不是答案的原因。稍后我可能会仔细看看。