使用Linux mktime获取时区

时间:2016-06-14 02:08:21

标签: c linux timezone

我使用以下代码来计算时区。当我将时区设置为亚洲/新加坡时,我认为我应该得到28800,其中28800/3600 = 8,它应该是GMT +8,但它返回27000/3600 = 7.5,我错了吗?

   struct tm tSysTime;
   long int secs;

   memset(&tSysTime,0,sizeof(tSysTime));
   tSysTime.tm_year = 70;
   tSysTime.tm_mon = 0;
   tSysTime.tm_mday = 1;
   tSysTime.tm_hour = 0;
   tSysTime.tm_min = 0;
   tSysTime.tm_sec = 0;
   secs = 0-mktime(&tSysTime);
   printf("[main] time zone %ld\n",secs);  

1 个答案:

答案 0 :(得分:4)

诊断

根据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中的0 - mktime(&tSysTime) 。我认为相关的数字是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

这是一个根深蒂固的谜团。不,不是。我有一对帮助的strptimetimestamp程序(偶尔使用bc)。

我住在'美国/太平洋'(官方,美国/洛杉矶,但我不喜欢这个名字 - 我住的地方离旧金山很近)时区(冬天的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做到这一点。