10

当您调用 mktime() 时,2 月 1 日似乎早于 1 月 31 日。这是为什么呢?我做错了什么还是glibc中的错误?

这是代码:

struct tm tm;
time_t tt;

memset(&tm, 0, sizeof(tm));
tm.tm_year = 2011;
tm.tm_mon = 1;
tm.tm_mday = 31;
tm.tm_hour = 11;
tm.tm_min = 41;
tm.tm_sec = 28;
tm.tm_isdst = 0;
tt = mktime(&tm);

printf("Time now %d-%d-%d %d:%d:%d (%s) = %lu\n",
    tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tt);


memset(&tm, 0, sizeof(tm));
tm.tm_year = 2011;
tm.tm_mon = 2;
tm.tm_mday = 1;
tm.tm_hour = 1;
tm.tm_min = 1;
tm.tm_sec = 1;
tm.tm_isdst = 0;
tt = mktime(&tm);

printf("Time now %d-%d-%d %d:%d:%d (%s) = %lu\n",
    tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, tt);

这是输出:

Time now 2011-2-3 11:41:28 (PST) = 61257325288
Time now 2011-2-1 1:1:1 (PST) = 61257114061

注意,初衷是比较两个time_t。这个问题导致第一个日期/时间似乎晚于第二个,这显然有点问题。

这只是使用“gcc test.c”编译并在 Ubuntu 9.10、gcc 版本 4.4.1(Ubuntu 4.4.1-4ubuntu8)、libc-2.10.1-0ubuntu15 上使用“./a.out”运行

在 32 位系统上,结果与预期一致 - 即与 64 位结果完全不同!

有人愿意确认/反驳这个结果和/或对我可能做错的事情有所了解吗?

4

2 回答 2

12

tm_mon 是从零开始的,因此您尝试设置 2 月 31 日,该日期已标准化。这是mktime()定义的链接。

于 2011-02-02T20:21:08.170 回答
3

为什么 2 月 1 日早于 1 月 31 日?

struct tm对成员的分配不正确。


.tm_mon是从零开始的

.tm_mon是基于零的@Jim Garrison

// tm.tm_mon = 1;
tm.tm_mon = 1 - 1; // For January

.tm.tm_year是基于 1900 年的

// tm.tm_year = 2011;
tm.tm_year = 2011 - 1900;

time_t打印说明符

"%ld"肯定不是 的匹配说明符time_t,因此会导致未定义的行为(UB)。time_t甚至可能不是整数类型。推荐一个广泛的签名类型或this。请注意,tt = mktime(&tm)错误时返回 -1 值,因此查看 -1 而不是无符号值非常有用。

// printf("%lu\n", tt);
printf("%lld\n", (long long) tt);

.tm_isdst

mktime()当地时间运行tm.tm_isdst = 0;断言时间戳是标准时间(对于 1 月左右的PST来说是合理的)。如果此代码在 1 月份的夏令时时区(例如Wellington)中运行,则报告的tm.tm_hour可能与预期不同。通常最好让mktime()推断.tm_isdst。否则,在跨越 DST 更改时,找到时间戳之间的差异(OP 的更高目标)可能会意外移动一个小时。

// tm.tm_isdst = 0;
tm.tm_isdst = -1;  // DST information is not available, mktime will adjust.
tt = mktime(&tm)
于 2021-07-15T20:59:49.783 回答