为什么美洲/芝加哥时区 (CST6CDT) 和 Etc/GMT-6 之间存在差异?

为什么美洲/芝加哥时区 (CST6CDT) 和 Etc/GMT-6 之间存在差异?

这是我的代码:

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

time_t my_timegm (struct tm *tm, char *tz_offset);

int
main (void)
{
  struct tm time_tm;
  time_t start_timet, end_timet;

  time_tm.tm_sec = 0;
  time_tm.tm_min = 0;
  time_tm.tm_hour = 0;
  time_tm.tm_mday = 1;
  time_tm.tm_mon = 0;
  time_tm.tm_year = 2023 - 1900;
  time_tm.tm_isdst = -1;
  start_timet = my_timegm (&time_tm, "Etc/GMT-6");
  printf ("\n%li ", start_timet);
  start_timet = my_timegm (&time_tm, "America/Chicago");
  printf ("\n%li ", start_timet);
}

my_timegm 是

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

time_t
my_timegm (struct tm *tm, char *tz_offset)
{
  time_t ret;
  char *tz;

  tz = getenv ("TZ");
  setenv ("TZ", tz_offset, 1);
  tzset ();
  ret = mktime (tm);
  if (tz)
    setenv ("TZ", tz, 1);
  else
    unsetenv ("TZ");
  tzset ();
  return ret;
}

输出是:

1672509600

1672552800

为什么会有 43200 秒(12 小时)的差异?或者,为什么 GMT-6 与 America/Chicago(UTC-6)不同?

答案1

归咎于 POSIX。

当环境变量的 POSIX 规范TZ最初创建时,正时区数字被分配给西半球的时区,因为这可能是各个 Unix 系统开发人员现有实践中可以达成的唯一共识......他们中的大多数或全部当时的总部都在美国大陆,所以他们不想在自己的地盘上开始使用那个讨厌的减号。

本质上,TZ=xxx-6将指定一个时区标记xxx,您可以通过从本地时间减去 6 小时来获取 UTC。

数据库zoneinfo(曾经被称为奥尔森时区数据库,现在由 IANA 维护Etc/GMTxx)出于遗留兼容性原因,对其时区使用相同的符号约定。

$ TZ=GMT-6 date              # legacy POSIX
Sun 11 Jun 10:23:18 GMT 2023 # note: GMT is a lie here!
$ TZ=Etc/GMT-6 date          # modern zoneinfo form
Sun 11 Jun 10:23:25 +06 2023

$ TZ=GMT6 date               # legacy POSIX
Sat 10 Jun 22:24:31 GMT 2023 # note: GMT is a lie here!
TZ=Etc/GMT+6 date            # modern zoneinfo form
Sat 10 Jun 22:24:35 -06 2023

请注意,当您使用该zoneinfo表单时,与时间戳(+06-06)一起显示的 UTC 偏移量与您可能期望的时区名称具有相反的符号zoneinfo

答案2

“我想获取经度,除以 15 并将其用作偏移量”

这里面有一个错误。根据这个推理,GMT 区域必须从 0 点向西延伸到 15 点,其他区域则从 15 点延伸到 30 点、30 点到 45 点等等。

但 GMT 时区从东经 7.5 延伸到西经 7.5。因此,西边的下一个区域是 7.5w 到 22.5w,然后是 22.5w 到 37.5w,依此类推。

这并不能解释您注意到的 12 小时差异,但确实指出了所需计算中的错误。

答案3

我刚刚在帖子里找到了答案date tz 使用 GMT 进行转换,并且具有相同 GMT 的城市名称会得到不同的结果,表明 GMT-x 实际上比 GMT 早 x 小时。这在我的代码中得到了验证。

int
main (void)
{
  struct tm time_tm;
  time_t start_timet, end_timet;

  time_tm.tm_sec = 0;
  time_tm.tm_min = 0;
  time_tm.tm_hour = 0;
  time_tm.tm_mday = 1;
  time_tm.tm_mon = 0;
  time_tm.tm_year = 2023 - 1900;
  time_tm.tm_isdst = 0;
  start_timet = my_timegm (&time_tm, "America/Chicago");
  printf ("\n%li ", start_timet);
  time_tm.tm_isdst = 0;
  start_timet = my_timegm (&time_tm, "Etc/GMT+6");
  printf ("\n%li ", start_timet);
}

相关内容