使用Clang编译器实现常规时间与Epoch时间互转的问题排查
Clang下日期时间与Epoch时间双向转换异常问题解决
我需要用Clang编译器实现常规日期时间和Epoch时间的双向转换,现有C代码在g下运行正常,但在本地Clang 14.0.0下运行异常,推测是strptime和strftime函数失效。以下是代码及两种编译器的输出:
// #include <chrono> #include <iostream> #include <cstring> uint64_t timeToEpoch(uint64_t day, uint64_t month, uint64_t year, uint64_t hour, uint64_t min, uint64_t second, uint64_t microsecond){ // std::cout << day << "-" << month << "-" << year << " " << hour << ":" << min << ":" << second << ":" << microsecond << std::endl; std::string timeT = std::to_string(day) + "-" + std::to_string(month) + "-" + std::to_string(year) + " " + std::to_string(hour) + ":" + std::to_string(min) + ":" + std::to_string(second); // std::cout << timeT << std::endl; char *time_T = new char[(timeT.length() + 1)]; strcpy(time_T, timeT.c_str()); // std::cout << time_T << std::endl; struct tm tm; strptime(time_T, "%d-%m-%Y %H:%M:%S", &tm); // std::cout << mktime(&tm) << std::endl; uint64_t t = mktime(&tm); t = (t * 1000000) + microsecond; return t; } std::string epochToTime(uint64_t epochTime){ std::string timeT; uint64_t microsecond = epochTime % 1000000; time_t epochTimeInSec = (epochTime - microsecond) / 1000000; char time_T[21]; strftime(time_T, 20, "%d-%m-%Y %H:%M:%S", localtime(&epochTimeInSec)); timeT = time_T; timeT = timeT + ":" + std::to_string(microsecond); return timeT; } int main() { std::cout << "Year changed 2004 to 2005\n"; uint64_t time_info_1 = timeToEpoch(31, 12, 2004, 23, 59, 59, 999999); uint64_t time_info_2 = timeToEpoch(1, 1, 2005, 0, 0, 0, 9); std::cout << "First timestamp in epoch :" << time_info_1 << "\n"; std::cout << "Second timestamp in epoch: " << time_info_2 << "\n\n"; std::cout << "Difference between both timestamp in microsecond: " << (time_info_2 - time_info_1) << "\n\n"; std::cout << "First timestamp converted from epoch: " << epochToTime(time_info_1) << "\n"; std::cout << "Second timestamp converted from epoch: " << epochToTime(time_info_2) << "\n"; return 0; }
g++输出:
Year changed 2004 to 2005 First timestamp in epoch :1104517799999999 Second timestamp in epoch: 1104517800000009 Difference between both timestamp in microsecond: 10 First timestamp converted from epoch: 31-12-2004 23:59:59:999999 Second timestamp converted from epoch: 01-01-2005 00:00:00:9
clang++输出:
Year changed 2004 to 2005 First timestamp in epoch :18446744073709551615 Second timestamp in epoch: 18446744073708551625 Difference between both timestamp in microsecond: 18446744073708551626 First timestamp converted from epoch: 19-01-586524 13:31::551615 Second timestamp converted from epoch: 19-01-586524 13:31::551625
问题原因
- 未初始化
struct tm变量:strptime只会填充匹配到的字段,未匹配的字段保留垃圾值,导致mktime返回-1(转换失败),强制转为uint64_t后溢出成最大值。 strptime是POSIX标准函数:Clang默认可能未启用POSIX扩展,导致函数无法正常工作。- 类型转换无安全检查:
time_t是有符号类型,直接转为无符号uint64_t会掩盖错误。
修复后的代码
#include <iostream> #include <cstring> #include <ctime> #include <stdexcept> // 定义POSIX宏,确保Clang识别strptime #define _POSIX_C_SOURCE 200809L uint64_t timeToEpoch(uint64_t day, uint64_t month, uint64_t year, uint64_t hour, uint64_t min, uint64_t second, uint64_t microsecond){ std::string timeT = std::to_string(day) + "-" + std::to_string(month) + "-" + std::to_string(year) + " " + std::to_string(hour) + ":" + std::to_string(min) + ":" + std::to_string(second); struct tm tm{}; // 初始化结构体为0,避免垃圾值 if (!strptime(timeT.c_str(), "%d-%m-%Y %H:%M:%S", &tm)) { throw std::invalid_argument("日期格式无效"); } tm.tm_isdst = -1; // 让mktime自动判断夏令时 time_t t = mktime(&tm); if (t == -1) { throw std::runtime_error("无法将tm转换为time_t"); } return static_cast<uint64_t>(t) * 1000000 + microsecond; } std::string epochToTime(uint64_t epochTime){ uint64_t microsecond = epochTime % 1000000; time_t epochTimeInSec = static_cast<time_t>((epochTime - microsecond) / 1000000); struct tm* local_tm = localtime(&epochTimeInSec); if (!local_tm) { throw std::runtime_error("无法将time_t转换为本地时间"); } char time_T[21]; if (strftime(time_T, sizeof(time_T), "%d-%m-%Y %H:%M:%S", local_tm) == 0) { throw std::runtime_error("格式化时间字符串失败"); } std::string timeT = time_T; timeT += ":" + std::to_string(microsecond); return timeT; } int main() { try { std::cout << "Year changed 2004 to 2005\n"; uint64_t time_info_1 = timeToEpoch(31, 12, 2004, 23, 59, 59, 999999); uint64_t time_info_2 = timeToEpoch(1, 1, 2005, 0, 0, 0, 9); std::cout << "First timestamp in epoch :" << time_info_1 << "\n"; std::cout << "Second timestamp in epoch: " << time_info_2 << "\n\n"; std::cout << "Difference between both timestamp in microsecond: " << (time_info_2 - time_info_1) << "\n\n"; std::cout << "First timestamp converted from epoch: " << epochToTime(time_info_1) << "\n"; std::cout << "Second timestamp converted from epoch: " << epochToTime(time_info_2) << "\n"; } catch (const std::exception& e) { std::cerr << "错误: " << e.what() << std::endl; return 1; } return 0; }
关键修复点
- 定义
_POSIX_C_SOURCE宏,启用POSIX扩展,确保Clang支持strptime。 - 初始化
struct tm为零值,清除垃圾值干扰。 - 设置
tm_isdst = -1,让mktime自动处理夏令时,避免转换错误。 - 添加函数调用的错误检查,抛出异常提示错误原因,避免无意义的溢出值。
- 安全处理类型转换,明确使用
static_cast,避免隐式转换导致的问题。
内容的提问来源于stack exchange,提问作者Akash Sagar
相关产品推荐
相关产品推荐

