【问题标题】:mktime or tz database unexpected return for 19411941 年的 mktime 或 tz 数据库意外返回
【发布时间】:2020-09-04 10:18:03
【问题描述】:

1941 年 7 月 3 日 (00:00:00) 和 1941 年 7 月 4 日 (00:00:00) 的 mktime 返回是出乎意料的。 两者相差82800秒,差一小时(3600)。

C 程序 diff1941.c(见下文)显示如下:

    $> diff1941

    july3=-899337600i
    diff:82800 should be 86400

一开始我以为是TZ数据库小时班,但据我了解,根据zdump命令,1941年没有这种班次。

    zdump -v -c 1940,1943 /etc/localtime

    /etc/localtime  Sun Feb 25 01:59:59 1940 UT = Sun Feb 25 01:59:59 1940 WET isdst=0 gmtoff=0
    /etc/localtime  Sun Feb 25 02:00:00 1940 UT = Sun Feb 25 03:00:00 1940 WEST isdst=1 gmtoff=3600
    /etc/localtime  Fri Jun 14 21:59:59 1940 UT = Fri Jun 14 22:59:59 1940 WEST isdst=1 gmtoff=3600
    /etc/localtime  Fri Jun 14 22:00:00 1940 UT = Sat Jun 15 00:00:00 1940 CEST isdst=1 gmtoff=7200
    /etc/localtime  Mon Nov  2 00:59:59 1942 UT = Mon Nov  2 02:59:59 1942 CEST isdst=1 gmtoff=7200
    /etc/localtime  Mon Nov  2 01:00:00 1942 UT = Mon Nov  2 02:00:00 1942 CET isdst=0 gmtoff=3600

所以在这一点上我很困惑。我的程序有一个我看不到的错误(可能),或者 lib C mktime 函数中有一个错误(不太可能),或者 TZ 数据库中有一些微妙的东西我找不到它(可能):怎么办你觉得呢?

我正在使用:

  • Ubuntu 20.04 64 位,
  • libc 2.31-0ubuntu9,
  • tzdata 2019c-3ubuntu1
  • /usr/share/zoneinfo/Europe/Paris 上的 /etc/localtime 点

diff1941.c:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

long int stamp(int d,int m,int y)
{
   struct tm date;
   memset(&date,0,sizeof(date));

   date.tm_mday=d;
   date.tm_mon=m-1;
   date.tm_year=y-1900;

   return mktime(&date);
}

int main(int argc, char **argv)
{
    if (argc>1)
        setenv("TZ","0",1);
    long int july3=stamp(3,7,1941);
    long int july4=stamp(4,7,1941);

    printf("july3=%ldi\n",july3);
    printf("diff:%ld should be 86400\n",july4-july3);
}

【问题讨论】:

  • 那段时间在法国与isdst=0 的约会不是无效的吗?使用 isdst=-1isdst=1 可以正常工作。
  • 我在这里运行了你的程序并打印了:july3=-899319600i diff:86400 should be 86400。我将America/New_York 用于 TZ 文件。您可能想尝试其他时区。您可能需要重新链接/etc/localtime 或添加拦截打开和重定向的共享库(例如LD_LIBRARY_PRELOAD
  • KamilCuk,你显然是对的。虽然我只是在 Ubuntu 18.04 主机上尝试过,但无论哪种方式都很好(idst=0、-1 或 1)。我仍然不明白为什么 7 月 3 日和 4 日的处理方式不同,而 isdst 强制为 0。如果没有其他人有更好的答案,我会接受你的。谢谢。
  • 好吧,我可以在Europe/France 和我的Europe/Warsaw 中重现你的行为。好吧,我相信“为什么”的答案将来自对 glibc mktime 函数的理解。

标签: c mktime ubuntu-20.04 tzdata


【解决方案1】:

通常,当您看到 1 小时的时差时,这意味着您应该查看夏令时设置。

在 1941 年 7 月 3 日和 1941 年 7 月 4 日这两个日期,法国都实行夏令时。您指定tm_isdst = 0,这意味着夏令时对您的日期无效。所以你的日期是无效的 - 没有像 1941 年 7 月 3 日这样的时间 00:00:00 没有 DST。

Glibc mktime tries it's best 来确定你有什么时间。实际上,它将日期中的第一个确定为 1941 年 7 月 3 日 02:00:00,将日期中的第二个确定为 1941 年 7 月 4 日 01:00:00。差是一天减去一小时。

设置isdst=-1 以让mktime“自动”确定您输入时间的当前夏令时。在法国,1941 年一直是 DST,它将确定isdst=1。或者通过设置date.isdst=1 明确指定您想要夏令时。

【讨论】:

  • 感谢您的回答,尤其是 glibc mktime 源代码的链接。
猜你喜欢
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
相关资源
最近更新 更多