C语言Unix时间戳转换异常:gmtime调用致旧指针失效
C语言gmtime调用引发的时间输出异常问题
当注释掉代码中标记的3行时,程序输出正常:
1st Printing of Timestamp (UTC): 08/19/2023 15:04:48 (Unix Epoch time: 1692457488) 2nd Printing of Timestamp (UTC): 08/19/2023 15:04:48 (Unix Epoch time: 1692457488)
取消这3行注释后,第二次输出的时间变成了当前系统UTC时间,但Unix时间戳仍正确:
1st Printing of Timestamp (UTC): 08/19/2023 15:04:48 (Unix Epoch time: 1692457488) 2nd Printing of Timestamp (UTC): 08/19/2023 20:27:57 (Unix Epoch time: 1692457488)
问题代码
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { // Get a Unix epoch value long long timestamp_ms = 1692457488113; char formatted_time[50]; // only need 20 characters to hold "MM/DD/YYYY HH:MM:SS" // Convert Unix timestamp to "MM/DD/YYYY HH:MM:SS" format in UTC time time_t timestamp_seconds = (time_t)(timestamp_ms / 1000); // Convert milliseconds to seconds struct tm *timestamp_timeinfo = gmtime(×tamp_seconds); // Use gmtime for UTC time // print result - should be 08/19/2023 15:04:48 (Unix Epoch time: 1692457488) strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", timestamp_timeinfo); printf("1st Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); /* time_t current_utc_time; // Get current UTC time grabbing variabluse I do nothing with (suspect gmtime memory leak) time(¤t_utc_time); struct tm *current_timeinfo = gmtime(¤t_utc_time); */ // print again, should be "08/19/2023 15:04:48 (Unix Epoch time: 1692457488)" but it is not strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", timestamp_timeinfo); printf("2nd Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); return 0; }
问题根源
gmtime函数返回的指针指向静态分配的全局缓冲区,所有对gmtime的调用都会复用这块内存。第一次调用gmtime时,缓冲区被填充为目标时间的struct tm数据;当取消注释后,第二次调用gmtime(¤t_utc_time)会覆盖这个缓冲区的内容,把它改成当前UTC时间。而你保存的timestamp_timeinfo指针依然指向这块被覆盖的缓冲区,所以第二次调用strftime时,读取的是被覆盖后的当前时间数据,导致输出异常。
解决方案
有两种可靠的修复方式:
1. 使用线程安全的gmtime_r(POSIX标准)
gmtime_r要求你自己提供struct tm缓冲区,避免依赖全局静态内存,从根本上杜绝覆盖问题:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { long long timestamp_ms = 1692457488113; char formatted_time[50]; time_t timestamp_seconds = (time_t)(timestamp_ms / 1000); struct tm timestamp_timeinfo; // 自己定义结构体变量 gmtime_r(×tamp_seconds, ×tamp_timeinfo); // 写入自己的缓冲区 strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", ×tamp_timeinfo); printf("1st Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); // 取消注释这部分也不会影响结果 time_t current_utc_time; time(¤t_utc_time); struct tm current_timeinfo; gmtime_r(¤t_utc_time, ¤t_timeinfo); strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", ×tamp_timeinfo); printf("2nd Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); return 0; }
2. 复制struct tm内容到本地变量
如果你的环境不支持gmtime_r,可以在第一次调用gmtime后,将返回的结构体内容复制到自己定义的变量中:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> // 用于memcpy int main() { long long timestamp_ms = 1692457488113; char formatted_time[50]; time_t timestamp_seconds = (time_t)(timestamp_ms / 1000); struct tm *temp_info = gmtime(×tamp_seconds); struct tm timestamp_timeinfo; memcpy(×tamp_timeinfo, temp_info, sizeof(struct tm)); // 复制静态缓冲区的内容 strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", ×tamp_timeinfo); printf("1st Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); // 取消注释这部分也不会影响结果 time_t current_utc_time; time(¤t_utc_time); struct tm *current_timeinfo = gmtime(¤t_utc_time); strftime(formatted_time, sizeof(formatted_time), "%m/%d/%Y %H:%M:%S", ×tamp_timeinfo); printf("2nd Printing of Timestamp (UTC): %s (Unix Epoch time: %lld)\n", formatted_time, timestamp_ms/1000); return 0; }
内容的提问来源于stack exchange,提问作者relayman357
相关产品推荐
相关产品推荐

