如何将UTC字符串解析为std::chrono::utc_clock::time_point?
UTC字符串解析为std::chrono::utc_clock::time_point的问题与解决方法
问题场景
给定UTC格式的字符串(如"2023-12-02 01:22:36.675349139 +00:00:00"),尝试解析为std::chrono::utc_clock::time_point时,结果总是出现时区偏移(本地时区为+9h,结果偏移-9h),使用的代码如下:
// 给定的字符串始终为UTC格式 //"2023-12-02 01:22:36.675349139 +00:00:00" std::istringstream ss(j.get<std::string>()); std::tm t = {}; ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S"); // 转换为time_point long timeSinceEpoch = std::mktime(&t); auto duration = std::chrono::seconds(timeSinceEpoch); time_point = std::chrono::utc_clock::time_point(duration); std::cout << "time_point: " << time_point << std::endl;
偏移原因
偏移出在std::mktime函数上:
std::get_time只是按格式把字符串解析到std::tm结构体里,不会处理时区,此时tm存储的就是UTC时间的各个字段。- 但
std::mktime的设计逻辑是把传入的std::tm当作本地时间,它会自动将这个"本地时间"转换为UTC时间戳。相当于你输入的UTC时间被当成了本地时间,再转一次UTC,自然会出现和本地时区相反的偏移。
简便可靠的解决方法
C++20及以上版本(优先推荐)
C++20的<chrono>库原生支持UTC时间字符串解析,不用手动处理时区,代码简洁且无歧义:
#include <chrono> #include <string> #include <iostream> int main() { std::string utc_str = "2023-12-02 01:22:36.675349139 +00:00:00"; // 直接解析为utc_clock的time_point,支持纳秒精度 auto tp = std::chrono::parse("%Y-%m-%d %H:%M:%S.%f %z", utc_str, std::chrono::utc_clock::time_point{}); std::cout << "time_point: " << tp << std::endl; return 0; }
%z格式符专门用来解析时区偏移(示例中的+00:00:00),std::chrono::parse会自动根据时区信息调整到正确的UTC时间点。- 原生支持高精度时间(比如示例里的纳秒部分),不需要额外处理。
C++20以下版本
如果无法升级到C++20,有两种替代方案:
方案1:用timegm替代mktime
timegm是POSIX标准函数(部分编译器支持),它的逻辑是把std::tm当作UTC时间直接转换为epoch时间戳,完美匹配需求:
std::istringstream ss(j.get<std::string>()); std::tm t = {}; ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S"); // timegm将tm视为UTC时间,直接生成正确的epoch时间戳 long timeSinceEpoch = timegm(&t); auto duration = std::chrono::seconds(timeSinceEpoch); auto time_point = std::chrono::utc_clock::time_point(duration); std::cout << "time_point: " << time_point << std::endl;
方案2:手动修正时区偏移
如果不能用timegm,可以先计算本地时区与UTC的偏移量,再修正mktime的结果:
std::istringstream ss(j.get<std::string>()); std::tm t = {}; ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S"); // 计算本地时区与UTC的偏移量 std::tm local_tm = t; time_t local_epoch = mktime(&local_tm); std::tm utc_tm = *gmtime(&local_epoch); long offset = mktime(&local_tm) - mktime(&utc_tm); // 修正时间戳得到正确的UTC epoch值 long timeSinceEpoch = mktime(&t) - offset; auto duration = std::chrono::seconds(timeSinceEpoch); auto time_point = std::chrono::utc_clock::time_point(duration); std::cout << "time_point: " << time_point << std::endl;
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

