9
#include <stdio.h>
#include <time.h>

int main(int argc, char* argv[])
{
    struct tm stm;
    stm.tm_sec = 27;
    stm.tm_min = 5;
    stm.tm_hour = 18;
    stm.tm_mday = 2;
    stm.tm_mon = 0;
    stm.tm_year = 43;
    stm.tm_wday = 0;
    stm.tm_yday = 0;
    printf("%d\n", mktime(&stm));
    getchar();
    return 0;
}

打印 -1

我有什么误解?

[+edit] 这是使用带有 32 位目标的 Visual Studio 2012。我想后续问题是“存储任意日期/时间值(即可能在 1900 年之前的那些)的推荐方法是什么?”

4

3 回答 3

17

在您的情况下,43(1943)被视为无效年份。原因是mktime返回一个time_t类型。这种类型并不是真正标准化的。文件说的是什么:

time_t类型是一个整数值,表示自 1970 年 1 月 1 日 00:00 UTC 以来经过的秒数。tm_year 是自 1900 年以来的年数

这个链接最终的 time_t typedef 是什么?说:

time_t表示自 Unix 纪元开始以来的秒数:1970 年 1 月 1 日午夜 UTC(不包括闰秒)。一些系统正确处理负时间值,而其他系统则不能

如果我们认为这time_t是一个有符号的 32 位整数,在最好的情况下,您可以在 ~ 13/12/1901 和 19/1/2038 之间创建日期

但是在您的情况下,实现不使用 的负数部分time_t,因此您不能使用 1970 之前创建日期mktime

于 2013-01-02T18:16:00.393 回答
3

time_t是您系统上的 64 位整数,并且您使用错误的格式标志说明符将其打印出来。您需要使用ll修饰符来指示它是 64 位:

time_t t = mktime(&stm);
printf("%lld", (int64_t)t);  // This will be correct if time_t is 32 or 64 bits

由于时间在纪元(1970 年 1 月 1 日)之前,因此时间是一个负值,如 -851910873,即 0xffffffffcd38df27 十六进制作为 64 位整数。当您尝试将其打印为 32 位整数时,您会得到高 32 位,即 0xffffffff 或 -1(尽管从技术上讲,根据 C 标准,这是未定义的行为,所以不要依赖它)。

正如其他人所提到的,time_t没有指定实际大小,所以你不应该对它做任何假设。如果您真的需要知道它有多大,最安全的做法是始终将其扩大到 64 位。

于 2013-01-02T18:38:07.803 回答
0

您试图表示日期“1943 年 1 月 2 日”。
在 Unix/Linux 系统上,此日期无法以time_t值表示,因为这些系统使用“1970 年 1 月 1 日”作为参考日期。

更新:
POSIX 指定mktime以“自纪元以来的秒数”返回时间(其中纪元 = 01-01-1970 00:00:00)。在严格的解释中,因此不能表示 1970 年 1 月 1 日之前的日期,因为“秒后”本质上是一个正数。

ANSI/ISO C 不太清楚mktime.

于 2013-01-02T18:26:40.693 回答