如何用std::chrono识别模糊本地时间并选择对应时间戳
用C++处理时区歧义本地时间的方法
一、歧义时间的产生原因
当本地时区实行夏令时回拨(比如UTC-8对应的太平洋时区在2023年11月5日凌晨2点回拨至1点),会导致某段本地时间(例如此次的1:00-2:00)对应两个不同的UTC时间,也就是两个不同的epoch时间,这就是时间歧义。
二、基于C++20 std::chrono的解决方案
C++20开始,std::chrono原生支持时区操作(需编译器版本支持:GCC 11+、Clang 13+),可通过以下步骤完成检测与处理:
1. 转换epoch时间到本地时区时间
先将epoch时间转为UTC时间(sys_time),再转换为目标时区的本地时间:
#include <chrono> #include <iostream> using namespace std::chrono; int main() { // 示例歧义对应的两个epoch时间 sys_seconds epoch1{seconds{1699173796}}; sys_seconds epoch2{seconds{1699177396}}; // 获取UTC-8对应的IANA时区(太平洋时区) const auto& tz = locate_zone("America/Los_Angeles"); // 转换为本地时间,两者结果一致 local_seconds local_time1 = tz.to_local(epoch1); local_seconds local_time2 = tz.to_local(epoch2); }
2. 检测本地时间是否存在歧义
调用时区对象的is_ambiguous方法,直接判断目标本地时间是否有歧义:
// 构造待检测的歧义本地时间 local_seconds target_local = local_days{November/5/2023} + 1h + 43min + 16s; bool is_ambiguous = tz.is_ambiguous(target_local); // 此处is_ambiguous返回true,说明该本地时间对应两个UTC时间
3. 获取歧义时间对应的最早/最晚epoch时间
通过to_sys的重载版本,传入choose::earliest或choose::latest参数,分别获取对应最早、最晚的UTC时间(即对应的epoch时间):
// 获取最早对应的epoch时间 sys_seconds earliest_sys = tz.to_sys(target_local, choose::earliest); std::cout << "最早epoch:" << earliest_sys.time_since_epoch().count() << std::endl; // 输出:1699173796 // 获取最晚对应的epoch时间 sys_seconds latest_sys = tz.to_sys(target_local, choose::latest); std::cout << "最晚epoch:" << latest_sys.time_since_epoch().count() << std::endl; // 输出:1699177396
三、注意事项
- 必须使用标准IANA时区标识符(如
America/Los_Angeles),不能直接用UTC-8,时区数据库无此标识。 - 若使用C20之前的版本,可使用第三方库
date.h(C20 chrono时区特性的前身),接口逻辑与上述一致。 - 部分旧编译器需手动链接时区相关库(如GCC需添加
-lstdc++fs参数,新版本已整合)。
内容的提问来源于stack exchange,提问作者Ranjith Ram
相关产品推荐
相关产品推荐

