linux/macos 下 tzname 和 timezone 不可靠,应读取 /etc/timezone 或解析 /etc/localtime 符号链接;macos 需用 system_profiler 或 corefoundation;windows 需映射注册表 id 到 iana 时区。

Linux/macOS 下用 tzname 和 timezone 不可靠
这两个全局变量在 C++ 标准中未定义行为,且依赖 localtime() 的调用顺序。很多系统(尤其是 musl libc)根本不初始化它们,tzname[0] 可能为空指针,直接解引用会崩溃。别信网上抄来的一行 std::string(tzname[0]) —— 那是赌运气。
推荐方案:读取 /etc/timezone 或解析 /etc/localtime
/etc/timezone 是 Debian/Ubuntu 系统的规范路径,内容通常是纯文本如 Asia/Shanghai;而大多数 Linux 发行版(包括 CentOS、Arch)用符号链接指向 /usr/share/zoneinfo/ 下的真实时区文件,比如:/etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai。
实操建议:
- 先尝试读
/etc/timezone,成功就直接返回内容(记得 trim 换行符) - 失败则检查
/etc/localtime是否为符号链接:readlink("/etc/localtime") - 若为链接,提取路径末尾的时区名(如
/usr/share/zoneinfo/Europe/Berlin→Europe/Berlin) - 注意:某些系统(如 Alpine)可能用硬链接或二进制 tzfile,此时需 fallback 到
getenv("TZ")或跳过
macOS 必须用 system_profiler 或 CoreFoundation
macOS 没有 /etc/timezone,/etc/localtime 是 tzfile 二进制格式,不能直接解析。最稳的方式是调用系统命令:
system_profiler SPSoftwareDataType | grep "Time Zone"
输出类似 Time Zone: Asia/Shanghai (CST, +0800),用 std::regex 提取括号前的部分即可。或者更轻量:用 CoreFoundation 的 CFLocaleCopyCurrent() + CFTimeZoneCopySystem(),但需链接 -framework CoreFoundation,跨平台构建时得加条件编译。
Windows 上用 GetDynamicTimeZoneInformation
Windows 不用 POSIX 时区名,而是用注册表时区 ID(如 China Standard Time),和 IANA 时区(Asia/Shanghai)不对应。想转成标准标识符,必须查映射表——微软提供官方 JSON 映射(timezone-mapping.json),但没内置 API。简易做法:
- 调用
GetDynamicTimeZoneInformation(&dtzi)获取dtzi.TimeZoneName - 硬编码常见映射(如
L"China Standard Time" → "Asia/Shanghai") - 生产环境建议集成
icu4c或用Boost.DateTime的时区数据库
跨平台代码里最容易被忽略的是:时区标识符不是“当前偏移量”,Asia/Kolkata 和 Asia/Dhaka 当前都 UTC+5:30,但它们 DST 规则不同,不能靠 gmtime 差值反推。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











