【问题标题】:mktime returns -1 when given a valid struct tm当给定一个有效的 struct tm 时,mktime 返回 -1
【发布时间】:2013-01-02 18:12:00
【问题描述】:
#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 年之前)的推荐方法是什么?”

【问题讨论】:

  • 为什么不检查errno 或使用perror 找出问题所在?
  • 有人删除了答案,即年份无效 - 我使用的 strptime 版本基于 1970 年而不是 1900 年的年份。
  • 我确实暂时删除了我的答案,我需要检查一些东西(我第一次是对的)

标签: c++ time


【解决方案1】:

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

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

这个链接What is ultimately a time_t typedef to? 说:

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

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

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

【讨论】:

  • 其实POSIX说time_t是有符号类型(link),所以当它实现为32位整数时,可以用来表示1970 年之前最多 68 年。
  • @Mat 这真的取决于实现,请完整阅读 Matteo Italia stackoverflow.com/questions/471248/… 的链接。 time_t 表示自 Unix 纪元开始以来的秒数:1970 年 1 月 1 日午夜 UTC(不包括闰秒)。一些系统正确处理负时间值,而其他系统
  • 这不是因为 time_t 已签名,因此执行了 1970 年之前的日期计算。由于标准对此没有任何说明,因此可能不会添加对 1970 年之前的日期的支持。
【解决方案2】:

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 位。

【讨论】:

    【解决方案3】:

    您试图表示日期“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 的结果是否存在负值。

    【讨论】:

    • time_t 已签名,1943 未超出范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多