当前位置: C语言 -- 专题 -- 非UTC时区localtime函数和gmtime函数返回相同值的原因及处理

非UTC时区localtime函数和gmtime函数返回相同值的原因及处理

localtime函数和gmtime函数是<time.h>头文件中声明的时间转换函数,其函数原型分别如下所示:

struct tm *localtime(const time_t *timer);
struct tm *gmtime(const time_t *timer);

localtime函数将time_t类型日历时间转换为本地时间表示的struct tm类型分解时间;gmtime函数将time_t类型日历时间转换为UTC时间表示的struct tm类型分解时间。对于相同的参数timer,如果本地时区是UTC区,两者之间没有差异;如果本地时区不是UTC区,两者之间相差的小时数等于时区差。以北京时间为例,北京时间是东八区,所以北京时间比UTC时间早8小时。


下面的代码反映了localtime函数和gmtime函数的这种关系。

time_t currentTime;
time(&currentTime);

printf("Beijing Time: %s\n", asctime(localtime(&currentTime)));
printf("%4cUTC Time: %s\n", ' ', asctime(gmtime(&currentTime)));

将输出:

Beijing Time: Wed Oct 03 14:35:30 2022

    UTC Time: Wed Oct 03 06:35:30 2022


如果使用指针分别接受localtime函数、gmtime函数的返回值,

time_t currentTime;
time(&currentTime);
struct tm *localPtr;
struct tm *gmPtr;

localPtr = localtime(&currentTime);   
gmPtr = gmtime(&currentTime);         

printf("Beijing Time: %s\n", asctime(localPtr));
printf("%4cUTC Time: %s\n", ' ', asctime(gmPtr));

将输出:

Beijing Time: Wed Oct 03 06:35:30 2022

    UTC Time: Wed Oct 03 06:35:30 2022

这种情况下输出的时间相同。


为什么会出现这种情况?这是因为localtime函数、gmtime函数返回的指针指向相同的静态对象(static object),后调用函数的数据会覆盖先前调用函数的数据。ISO/IEC 9899:2018标准第7.27.3 Time conversion functions节也对这种情况作了规定,标准原文:Except for the strftime function, these functions each return a pointer to one of two types of static objects: a broken-down time structure or an array of char. Execution of any of the functions that return a pointer to one of these object types may overwrite the information in any object of the same type pointed to by the value returned from any previous call to any of them and the functions are not required to avoid data races with each other.。这里these functions指的是asctimectimelocaltimegmtime函数,其中localtime函数和gmtime函数返回的是指向分解时间的指针。


为防止数据被覆盖,可以使用安全函数,例如:localtime_s函数、gmtime_s函数;也可以使用变量对先前的数据进行备份。

time_t currentTime;
time(&currentTime);
struct tm localStruc;
struct tm gmStruc;

localStruc = *localtime(&currentTime);   
gmStruc = *gmtime(&currentTime);         

printf("Beijing Time: %s\n", asctime(&localStruc));
printf("%4cUTC Time: %s\n", ' ', asctime(&gmStruc));

将输出:

Beijing Time: Wed Oct 03 14:35:30 2022

    UTC Time: Wed Oct 03 06:35:30 2022