【问题标题】:Using Linux mktime to get timezone使用 Linux mktime 获取时区
【发布时间】:2023-03-26 13:52:01
【问题描述】:

我使用以下代码来计算时区。当我将时区设置为亚洲/新加坡时,我想我应该得到 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);  

【问题讨论】:

  • 请查看URL,这将有助于提高您的内容质量

标签: c linux timezone


【解决方案1】:

诊断

根据 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

这是一个根深蒂固的谜团。不,不是。我有两个程序,strptimetimestamp 有帮助(加上随意使用的 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 做到这一点。

【讨论】:

  • 非常感谢,不过新加坡的时区实际上是GMT8,我应该怎么解决这个问题,自己修改tzdata?
  • 新加坡当前的时区偏移量是 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(&amp;tSysTime) 中的 0。我相信相关号码是946684800
  • 多好!再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-24
  • 2010-10-06
  • 1970-01-01
  • 2015-11-10
  • 2014-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多