c++20 推荐用 std::chrono::current_zone()->get_info(now).offset.to_string() 获取时区偏移;否则回退到 mktime/gmtime 差值法跨平台计算,避免依赖全局变量或平台 api。

用 std::chrono::current_zone() 获取时区信息(C++20)
如果你的编译器支持 C++20 且启用了 <chrono></chrono> 的时区扩展(如 GCC 13+、Clang 15+、MSVC 19.34+),最直接的方式是调用 std::chrono::current_zone()。它返回一个 const std::chrono::time_zone*,再通过 get_info() 查询当前时间点的偏移。
注意:该接口依赖系统时区数据库(如 IANA tzdata),若系统未安装或路径异常(例如嵌入式环境),current_zone() 可能抛出 std::runtime_error 或返回空指针。
示例关键片段:
auto now = std::chrono::system_clock::now(); auto tz = std::chrono::current_zone(); auto info = tz->get_info(now); std::string offset_str = info.offset.to_string(); // 如 "+08:00"
这里 info.offset 是 std::chrono::seconds 类型,to_string() 是 C++20 新增成员函数,格式固定为 ±HH:MM(不带秒)。
fallback 到 std::localtime() + timezone 全局变量(POSIX 兼容)
在 C++20 不可用或时区库被禁用的场景(如旧版 GCC、某些交叉编译环境),需退回到 POSIX 接口。核心思路是:调用 std::time(0) 获取秒数,用 std::localtime() 转为 struct tm,再结合 timezone 和 daylight 全局变量计算偏移。
容易踩的坑:
-
timezone是 UTC 到本地标准时间的秒数偏移(注意:是“标准时间”,不含夏令时) -
daylight非零表示当前启用夏令时,此时真实偏移 =timezone - 3600(假设 DST 为 +1 小时) - 但
daylight仅反映系统是否配置了 DST 规则,不保证当前时刻正在生效 —— 必须配合tm.tm_isdst判断
更稳妥的做法是用 std::mktime() 反向推算(见下条)。
用 std::mktime() 和 std::gmtime() 差值算偏移(跨平台可移植)
这是最通用、不依赖全局变量或时区数据库的方法,适用于所有符合 ISO C++ 标准的实现(包括 MSVC、MinGW、iOS 等)。原理:构造一个已知 UTC 时间的 struct tm,用 std::mktime() 转成 time_t;再用 std::gmtime() 将同一 time_t 转回 UTC 的 struct tm,两者差值即为本地偏移秒数。
实操要点:
- 选一个不会触发闰秒、且
tm_isdst = 0的时间点(如 2000-01-01 00:00:00 UTC) - 手动填充
tm时,tm_year是自 1900 年起的年份,tm_mon从 0 开始,tm_isdst = -1让系统自动判断(但此处建议显式设为 0 避免歧义) - 结果秒数转字符串时注意符号和补零:
offset_seconds / 3600得小时,abs(offset_seconds % 3600) / 60得分钟
简略示意:
std::tm utc_tm = {};
utc_tm.tm_year = 100; // 2000
utc_tm.tm_mon = 0; // Jan
utc_tm.tm_mday = 1;
utc_tm.tm_hour = 0;
utc_tm.tm_min = 0;
utc_tm.tm_sec = 0;
utc_tm.tm_isdst = 0;
std::time_t t = std::mktime(&utc_tm); // 转成本地 time_t
std::tm* gm = std::gmtime(&t);
// gm->tm_hour 等是 UTC 时间,与原始 utc_tm 比较即可得偏移
不过更推荐直接用 difftime(std::mktime(&local_tm), std::mktime(&utc_tm)),避免手动解析 tm 字段。
为什么不用 _get_timezone() 或 GetTimeZoneInformation()?
Windows 下有 _get_timezone()(返回秒数)和 GetTimeZoneInformation()(返回结构体),Linux 下有 tzset() + timezone。但这些全是平台专属 API,破坏可移植性;且 Windows 的 _get_timezone() 返回的是标准时间偏移,不随 DST 自动更新 —— 它和 tm_isdst 是脱节的。
真正麻烦的不是获取数值,而是“当前”二字:偏移可能因夏令时切换而变化,而系统 API 往往只提供静态配置或模糊状态。所以最稳的路径仍是基于当前 time_t 做一次本地/UTC 双向转换,让 libc 自己处理规则。
别忘了检查 std::mktime() 返回值是否为 -1,这代表输入时间无效(比如 2024-02-30),某些老旧 libc 在边界日期上会失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











