【问题标题】:Linux-x64 glibc: Why does Feb 1 come before Jan 31?Linux-x64 glibc:为什么 2 月 1 日早于 1 月 31 日?
【发布时间】:2011-06-20 05:49:56
【问题描述】:

当您调用 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。这个问题导致第一个日期/时间似乎晚于第二个,这显然有点问题。

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

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

是否有人愿意确认/反驳这个结果和/或对我可能做错的地方提供一些见解?

【问题讨论】:

    标签: c++ c linux glibc mktime


    【解决方案1】:

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

    【讨论】:

    • 简单来说,2月31日(实际上是3月3日或3月2日)比3月1日晚。
    • 谢谢吉姆 - 有点无聊;)不知道我在 RTFM 多次后怎么错过了!
    • @Paul - 我们都有这样的时刻——我所拥有的比我想记住的要多:-)
    • 这与 32 位和 64 位无关。 mktime 将超出范围的日期标准化,因此如果您将月份设置为 2 月 (1),将日期设置为 31,然后调用 mktime(),结果将是 3 月 3 日(非闰年;闰年的 3 月 2 日)。
    【解决方案2】:

    为什么 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; 断言时间戳是标准时间(对于PST 大约在一月是合理的)。如果此代码在 1 月份 daylight 时间的时区运行(例如 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)
    

    【讨论】:

    • 好好清理——很棒的暑期项目,我们缺乏正常的学生潮......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多