10

在 Ubuntu 12.04.3 LTS 机器上工作时,我注意到 localtime() 和 localtime_r() 在进程生命周期内系统的时区更改时表现不同:localtime() 立即获取时区更改,而 localtime_r() 确实不,它似乎坚持流程启动时的时区。这是预期的行为吗?我在任何地方都没有看到这个。

更准确地说,当我使用以下代码时......

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

int main() {
  while (1) {
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);
    printf("localtime:%02d/%02d/%02d-%02d:%02d:%02d\n",
           tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
    sleep(1);
  }
  return 0;
}

...并通过...从UTC更改时区

# echo 'Europe/Berlin' > /etc/timezone 
# sudo dpkg-reconfigure --frontend noninteractive tzdata

...然后代码产生以下内容,...

localtime:10/04/2013-01:11:33
localtime:10/04/2013-01:11:34
localtime:10/04/2013-01:11:35
localtime:10/03/2013-23:11:36
localtime:10/03/2013-23:11:37
localtime:10/03/2013-23:11:38

...但如果我使用:

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

int main() {
  while (1) {
    time_t t = time(NULL);
    struct tm local_tm;
    struct tm *tm = localtime_r(&t, &local_tm);    
    printf("localtime_r:%02d/%02d/%02d-%02d:%02d:%02d\n",
           tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
    sleep(1);
  }
  return 0;
}

...然后在进行类似的时区更改时没有任何变化:

localtime_r:10/04/2013-01:15:37
localtime_r:10/04/2013-01:15:38
localtime_r:10/04/2013-01:15:39
localtime_r:10/04/2013-01:15:40
localtime_r:10/04/2013-01:15:41
localtime_r:10/04/2013-01:15:42

更新:在调用 localtime_r() 之前添加对 tzset() 的调用会产生预期的行为。从规范/手册页是否清楚(参见下面的讨论)是mentalhealth.stackexchange.com 的问题......

4

1 回答 1

8

请参阅以下文档:

localtime() 函数将日历时间 timep 转换为分解的时间表示,表示相对于用户指定的时区。该函数的行为就好像它调用了 tzset(3) 并使用有关当前时区的信息设置外部变量 tzname,使用协调世界时 (UTC) 和本地标准时间之间的差异(以秒为单位)设置时区,如果是日光,则将日光设置为非零值储蓄时间规则适用于一年中的某些时候。返回值指向一个静态分配的结构,随后调用任何日期和时间函数可能会覆盖该结构。localtime_r() 函数的作用相同,但将数据存储在用户提供的结构中。它不需要设置 tzname、时区和日光。

来自: http: //linux.die.net/man/3/localtime_r

据我所知,代码似乎按我的预期工作。

编辑以从同一文档中添加更多内容:

根据 POSIX.1-2004,localtime() 的行为就像调用了 tzset(3) 一样,而 localtime_r() 没有这个要求。对于可移植代码 tzset(3) 应该在 localtime_r() 之前调用。

于 2013-10-03T23:29:22.307 回答