这是我的代码:
#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);
}