为啥 glibc "timezone" global 与 DST 上的系统时间不一致?

Posted

技术标签:

【中文标题】为啥 glibc "timezone" global 与 DST 上的系统时间不一致?【英文标题】:Why does glibc "timezone" global not agree with system time on DST?为什么 glibc "timezone" global 与 DST 上的系统时间不一致? 【发布时间】:2010-10-12 18:08:06 【问题描述】:

我遇到了一个奇怪的问题,我的系统时钟知道这是夏令时,但 glibc 似乎不知道。这是一个最新的 Ubuntu 安装,我检查了 /etc/localtime,它有正确的转换时间,适合上周切换到 DST。

我当前正确的时区是太平洋夏令时间 (UTC-7)。当我询问我的系统我在哪个时区时,它会正确地告诉我:

$ date +%z
-0700

但是当我运行以下程序时:

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

int main() 
  tzset();
  printf("%lu\n", timezone);
  return 0;

输出错误:

28800

对应于 UTC-8 或太平洋标准时间。 (不,我的环境中没有设置 TZ)

我认为 glibc 和 date 程序会从同一个来源获取他们的时区信息,但显然要么他们没有,要么我误解了 glibc 全局时区的工作原理。

那么基本问题是:

    为什么这两个输出不同 如何可靠地检测来自 C 程序的系统 UTC 偏移量?

【问题讨论】:

【参考方案1】:

我不认为“时区”会随着日光时间而变化。尝试“日光”变量。在我的系统上:

外部变量 timezone 包含差异,以秒为单位, 在 UTC 和当地标准时间之间(例如,在美国东部 时区(EST),时区为 5*60*60)。外部变量日光 仅当在 TZ 环境变量。

【讨论】:

我对 tzset 手册页的阅读表明,dayllight 变量仅表明本地区域是否在某个时候使用夏令时,并不一定表明它当前是否有效。 我想我同意你的看法。我建议 time_t t = time(NULL); printf("%d\n",(int)difftime(mktime(gmtime(&t)),t)); 但这给了我与“时区”相同的结果。【参考方案2】:

执行此操作后查看 tm.tm_isdst 字段:

  time_t current_time;
  struct tm tm;

  current_time = time(NULL);
  localtime_r(&current_time, &tm);

根据 localtime_r(3) 联机帮助页,这确实表明 DST 在指定时间是否有效。我认为您需要假设 DST 为您已经使用的 timezone(3) 变量增加了一小时,或者针对 GMT 执行差异技巧。

在澳大利亚 AEST 对我有用,希望对你有用。

【讨论】:

【参考方案3】:

您可以使用 struct tm 的tm_gmtoff 成员,它与 ::timezone 相同,但它考虑 DST 并且符号相反。

http://www.gnu.org/s/libc/manual/html_node/Time-Zone-Functions.html#Time-Zone-Functions

【讨论】:

标准struct tm中没有tm_gmtoff【参考方案4】:

如果定义了 linux,这是我使用 tm_gmtoff 的代码,否则使用 gettimofday 中的 timezone.tz_minuteswest(这里的 'ltm' 是本地时间的输出):


    int tz_offset;

#if defined(__linux__)
    tz_offset= ltm.tm_gmtoff;
#else
    tz_offset= -tz.tz_minuteswest*60 + ltm.tm_isdst*3600;
#endif

     printf ("LT = UTC +d sec\n", tz_offset);

【讨论】:

以上是关于为啥 glibc "timezone" global 与 DST 上的系统时间不一致?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 "map! <C-q> :q <CR> " 在 vi​​m 中不起作用?

为啥我在php中用date()函数获取的时间老师与我电脑上显示的差8小时?

为啥 python datetime replace timezone 返回不同的时区?

为啥使用Hibernate开发web项目的时候在servlet头上使用@webServlet(name="index",urlPatterns="/index&q

为啥 fread 循环需要额外的 Ctrl+D 来用 glibc 发出 EOF 信号?

/lib64/libc.so.6:未找到版本“GLIBC_2.14”。为啥我会收到此错误?