奇怪的mktime逻辑,负秒

时间:2013-11-20 18:56:21

标签: c time libc mktime

我一直在使用mktime / localtime进行时间管理,包括对日期/时间的一些重要算法。

在向mktime提供包含负值的struct tm时,我发现了一些非常奇怪的东西。

请使用以下代码。洛杉矶在2013年11月3日有一个DST更改。如果我指定时间为2013-11-04午夜时间并减去24小时,我得到的值与2013-11-03午夜相同。这与UTC方式相差25小时,这很好,因为isdst = -1可以说我们正在查看“挂钟 - 时间”。如果我减去1440分钟(24 * 60)则相同。但是,如果我减去86400(24 * 60 * 60)秒,我得到2013-11-03凌晨1点。这是UTC方式的24小时差异。这是以下代码的输出:

2013-11-03 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000
2013-12--27 00:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000
2013-11-04 -24:00:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000
2013-11-04 00:-1440:00 (gmtoff=0, isdst=-1) -> 2013-11-03 00:00:00 (gmtoff=-25200, isdst=1) -> 1383462000
2013-11-04 00:00:-86400 (gmtoff=0, isdst=-1) -> 2013-11-03 01:00:00 (gmtoff=-25200, isdst=1) -> 1383465600

对我来说它没有意义 - 为什么秒的处理方式与分钟,小时和天数不同?我看着男人和C标准,却找不到任何东西。

这种行为打破了我的一些假设并使事情复杂化。有人知道mktime / localtime的一个很好的替代品(我测试过boost,ICU和tzcode,对于我需要的东西来说太慢了)。

提前感谢任何想法:)

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* printtm(struct tm tm)
{
  static char buf[100];
  sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d (gmtoff=%ld, isdst=%d)",
    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
    tm.tm_hour, tm.tm_min, tm.tm_sec,
    tm.tm_gmtoff, tm.tm_isdst);
  return buf;
}

void test(int y, int m, int d, int hh, int mm, int ss, int isdst)
{
  struct tm tm;
  memset(&tm, 0, sizeof(tm));
  tm.tm_year = y - 1900;
  tm.tm_mon = m - 1;
  tm.tm_mday = d;
  tm.tm_hour = hh;
  tm.tm_min = mm;
  tm.tm_sec = ss;
  tm.tm_isdst = isdst;
  printf("%s -> ", printtm(tm));
  time_t t = mktime(&tm);
  printf("%s -> %ld\n", printtm(tm), t);
}


int main()
{
  setenv("TZ", ":America/Los_Angeles", 1);
  tzset();

  test(2013,11,03, 0,0,0, -1);
  test(2013,12,-27, 0,0,0, -1);
  test(2013,11,04, -24,0,0, -1);
  test(2013,11,04, 0,-1440,0, -1);
  test(2013,11,04, 0,0,-86400, -1);

  return 0;
}

1 个答案:

答案 0 :(得分:3)

mktimestruct tm中使用tm_isdst==-1超出范围的值是有问题且未明确的。就个人而言,我认为你的系统在这里表现的方式是错误的,但标准并不清楚它应该如何表现,因此任何这样的使用都是不可移植的。要对struct tm进行算术运算,您应该确保事先将tm_isdst设置为0或1,以便明确结果。

请注意,执行此操作的一种简单方法是,在应用算法确定日光时间是否生效之前,只需在原始mktimestruct tm)上调用tm_isdst==-1即填写tm_isdst的确定值,然后在进行算术调整后再次调用它。