time.h中的tzset和daylight全局变量解释

时间:2015-11-30 06:42:49

标签: c timezone dst

在daylight全局变量的time.h标题中,它说:  “如果夏令时规则适用,则此变量具有非零值。非零值并不一定意味着夏令时现在有效;它表示只有夏令时有时生效。”

现在我注意到,在Solaris 11.2和Linux中,“daylight”变量被设置为1,即使我的时区根本不使用夏令时(澳大利亚/布里斯班)。

示例代码确认了这一点,如果我运行tzset并输出我们得到的全局变量: daylight = 1 tz [0] = [AEST] tz [1] = [AEDT] timezone = [-36000]

但根据我的理解,日光应该设置为0,因为我的区域在一年中的任何时候都没有夏令时。

我还注意到,当设置为当前时间时,struct tm返回tm_isdst = 0,这是正确的。

那么为什么daylight变量设置为1?不应该设置为0吗?还是我误解了这个?

代码是:

#include <stdio.h>
#include <time.h>
void main()
{
  time_t t;
  struct tm     *tms = { 0 };
  tzset();
  time(&t);
  tms = localtime(&t);
  printf("date and time : %s",ctime(&t));
  printf("daylight = %d tz[0] = [%s] tz[1] = [%s] timezone = [%ld]\n", daylight, tzname[0], tzname[1], timezone);
  printf("tm_isdst = %d\n",tms->tm_isdst);
}

输出是:

date and time : Mon Nov 30 16:41:01 2015
daylight = 1 tz[0] = [AEST] tz[1] = [AEDT] timezone = [-36000]
tm_isdst = 0

3 个答案:

答案 0 :(得分:6)

关于C标准tm_isdst成员。

  

如果夏令时生效,则tm_isdst的值为正,如果夏令时不生效,则为零,如果信息不可用,则为负。 C11dr§7.27.14

这与* nix规范略有不同,关于* nix全局变量daylight daylight不属于标准C.

gnu.org报告

  

变量:int daylight
  如果应用夏令时规则,则此变量具有非零值。非零值并不一定意味着夏令时现在生效;这意味着只有夏令时有时才有效。

tm_isdst指的是struct tm时间戳。它只表示DST对该时间戳有效。

daylight != 0表示有时在时区的时间戳中使用DST。

正如澳大利亚/布里斯班曾经观察过DST之前(@Jon Skeet)到1972年,daylight == 1是合理的daylight意味着DST在该时区的某段时间内有效(可能自1970年以来)。

OP的“......即使我的时区根本不使用夏令时”也不正确。

以下代码显示自1970年以来“澳大利亚/布里斯班”使用DST(至少timezone DB认为如此)。

#include<time.h>
#include<stdlib.h>
#include<sys/time.h>

int main(void) {
  setenv("TZ", "Australia/Brisbane", 1);
  tzset();
  time_t now;
  time(&now);
  struct tm tm;
  int isdst = 42; // See Hitchhiker's_Guide_to_the_Galaxy
  time_t t;
  for (t = 0; t < now; t += 3600) {
    tm = *localtime(&t);
    if (tm.tm_isdst != isdst) {
      printf("dst:%d %s", tm.tm_isdst, ctime(&t));
      isdst = tm.tm_isdst;
    }
  }
  printf("dst:%d %s", tm.tm_isdst, ctime(&t));
  return 0;
}

输出

dst:0 Thu Jan  1 10:00:00 1970
dst:1 Sun Oct 31 03:00:00 1971
dst:0 Sun Feb 27 02:00:00 1972
dst:1 Sun Oct 29 03:00:00 1989
dst:0 Sun Mar  4 02:00:00 1990
dst:1 Sun Oct 28 03:00:00 1990
dst:0 Sun Mar  3 02:00:00 1991
dst:1 Sun Oct 27 03:00:00 1991
dst:0 Sun Mar  1 02:00:00 1992
dst:0 Tue Dec  1 16:00:00 2015

答案 1 :(得分:3)

澳大利亚/布里斯班目前不使用夏令时 ,但过去曾有过这样的时间。查看australasia文件,您会看到它观察到DST的几年。

我对daylight的解释是,它表明该时区是否曾经曾经观察(或将会遵守现行规则)夏令时。换句话说,如果这是1,那么在执行日期/时间处理时需要小心,而如果它是0,则可以假设一个恒定的UTC偏移。

(我不能立即清楚一个从未观察过DST但是 随时间移动了标准UTC偏移的时区,是否将daylight设置为1。猜测设置它是完全错误的,但出于上述原因这样做是可行的......)

答案 2 :(得分:0)

如果考虑tzset()会更容易-它会安装时区定义。也就是说,它解释了TZ环境变量的内容,加载了zoneinfo文件或类似文件。 tzset()不会做的一件事就是根据任何特定时间提供信息,例如,它不会查看系统时钟或对当前年份进行假设。有一些标准函数,例如gmtime(),localtime(),mktime()可以处理特定的日期和时间。 tzset()只是为这些功能建立了通用框架,并在外部变量中提供了有关整体时区定义的一些不同的基本信息。 tzset()不会告诉您现在是否有夏令时,因为它不知道或不在乎“现在”是什么。它可以告诉您整个时区定义是否包含有关夏时制的任何信息,例如是否定义tz [1]。

似乎某些文档也已过时,因为它未能明确指定tzset()如何在其外部变量中显示更现代/复杂的时区定义,但了解tzset()的作用大部分后就可以清楚了从它。

“ daylight”和“ timezone”以及一些文档的问题在于,它们是在时区定义仅是TZ字符串的很早就创建的,TZ字符串具有可以指定名称和时间偏移以及诸如“ DST”之类的语法从3月1日星期日开始,至10月3日星期日结束”。它不包含任何历史信息,如果时区的规则已更改,那么您只需更改TZ变量即可实施新规则。现在,我们有了带历史信息的zoneinfo数据库之类的东西,不幸的是tzset()的定义跟不上这个。在内部很好:当tzset()加载复杂的时区时,localtime()等将做正确的事情,但是简单的extern变量不能总是给出准确的摘要。 “夏令时”还算不错:因为tzset()没有考虑任何特定的日期/时间,所以如果在时区数据中的任何地方定义了任何夏令时,则将其设置为“夏令时”是合理的。定义了tz [1]。原则上,时区中的几乎所有内容都可以随时间变化,包括时区名称和基本时区偏移量。这种情况很少发生,但是某些实时时区具有不寻常的历史,尤其是在国际日期变更线附近。