诊断
根据 Mac 上的zdump -v Asia/Singapore,1965 年 8 月至 1982 年 1 月期间新加坡与 UTC 的时区偏移量为 UTC 以东 7 小时 30 米:
$ zdump -v Asia/Singapore
Asia/Singapore Fri Dec 13 20:45:52 1901 UTC = Sat Dec 14 03:41:17 1901 SMT isdst=0
Asia/Singapore Sat Dec 14 20:45:52 1901 UTC = Sun Dec 15 03:41:17 1901 SMT isdst=0
Asia/Singapore Wed May 31 17:04:34 1905 UTC = Wed May 31 23:59:59 1905 SMT isdst=0
Asia/Singapore Wed May 31 17:04:35 1905 UTC = Thu Jun 1 00:04:35 1905 MALT isdst=0
Asia/Singapore Sat Dec 31 16:59:59 1932 UTC = Sat Dec 31 23:59:59 1932 MALT isdst=0
Asia/Singapore Sat Dec 31 17:00:00 1932 UTC = Sun Jan 1 00:20:00 1933 MALST isdst=1
Asia/Singapore Tue Dec 31 16:39:59 1935 UTC = Tue Dec 31 23:59:59 1935 MALST isdst=1
Asia/Singapore Tue Dec 31 16:40:00 1935 UTC = Wed Jan 1 00:00:00 1936 MALT isdst=0
Asia/Singapore Sun Aug 31 16:39:59 1941 UTC = Sun Aug 31 23:59:59 1941 MALT isdst=0
Asia/Singapore Sun Aug 31 16:40:00 1941 UTC = Mon Sep 1 00:10:00 1941 MALT isdst=0
Asia/Singapore Sun Feb 15 16:29:59 1942 UTC = Sun Feb 15 23:59:59 1942 MALT isdst=0
Asia/Singapore Sun Feb 15 16:30:00 1942 UTC = Mon Feb 16 01:30:00 1942 JST isdst=0
Asia/Singapore Tue Sep 11 14:59:59 1945 UTC = Tue Sep 11 23:59:59 1945 JST isdst=0
Asia/Singapore Tue Sep 11 15:00:00 1945 UTC = Tue Sep 11 22:30:00 1945 MALT isdst=0
Asia/Singapore Sun Aug 8 16:29:59 1965 UTC = Sun Aug 8 23:59:59 1965 MALT isdst=0
Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0
Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0
Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0
Asia/Singapore Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 11:14:07 2038 SGT isdst=0
Asia/Singapore Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 11:14:07 2038 SGT isdst=0
$
因此,您得到的结果是 1970-01-01 与新加坡 UTC 的正确偏移量。
附属问题
新加坡的当前时区是 GMT8。我应该怎么做才能解决这个问题?
新加坡当前的时区偏移量是 UTC+8 (GMT+8),但历史上(特别是 1970 年)并非如此。当数据库中的时区偏移正确时,您必须设计一个更接近当前时间的时间。这似乎意味着自 1982-01-01 00:30:00 +08:00 以来的时间。那么,也许您应该使用 2000-01-01 00:00:00?您需要从 1970-01-01 00:00:00 开始的 30 年中的秒数才能得到正确的答案,并且您将使用它来代替 0 - mktime(&tSysTime) 中的 0。我相信相关号码是946684800。
修改后的 C 代码
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void)
{
struct tm tSysTime;
long int secs;
memset(&tSysTime,0,sizeof(tSysTime));
tSysTime.tm_year = 100;
tSysTime.tm_mon = 0;
tSysTime.tm_mday = 1;
tSysTime.tm_hour = 0;
tSysTime.tm_min = 0;
tSysTime.tm_sec = 0;
secs = 946684800 - mktime(&tSysTime);
printf("[main] time zone %ld\n",secs);
return 0;
}
示例运行
$ TZ=Asia/Singapore tzoff
[main] time zone 28800
$ TZ=US/Pacific tzoff
[main] time zone -28800
$ TZ=UTC0 tzoff
[main] time zone 0
$
你是怎么找到946684800的
这是一个根深蒂固的谜团。不,不是。我有两个程序,strptime 和 timestamp 有帮助(加上随意使用的 bc)。
我住在“美国/太平洋”时区(官方名称是 America/Los_Angeles,但我不太喜欢这个名字——我住的离旧金山更近)时区(冬季 UTC-08:00;夏季 UTC-07:00)。
$ strptime '2000-01-01 00:00:00'
946713600 = 2000-01-01 00:00:00
$ timestamp 946713600
946713600 = Sat Jan 01 00:00:00 2000
$ timestamp -Z 946713600
946713600 = Sat Jan 01 00:00:00 2000 -08:00
$ bc <<< '946713600 - 8 * 3600'
946684800
$ timestamp -Z 946684800
946684800 = Fri Dec 31 16:00:00 1999 -08:00
$ TZ=UTC0 timestamp -Z 946684800
946684800 = Sat Jan 01 00:00:00 2000 +00:00
$
如果您花时间研究如何做,您可能可以使用 GNU date 做到这一点。