最可靠方案是用 std::put_time 配合 std::gmtime 反推本地时区偏移并手动拼接带冒号的 +hh:mm,避免 strftime %z 不可移植及手写格式错误;c++20 起推荐 std::chrono::zoned_time 与 std::format。

直接用 std::put_time 配合 std::gmtime 或 std::localtime 最可靠,别手写格式化逻辑。
为什么不用 strftime 直接套 ISO 8601?
strftime 的 %z 在 Windows MSVC 下不输出带冒号的时区(如 +08:00),而是 +0800;%:z 是 GNU 扩展,不可移植。ISO 8601 要求时区分隔冒号(如 2024-05-20T13:45:30+08:00),标准 C++ 库原生不支持 %:z。
- Linux/GCC 可能工作,但跨平台项目会出问题
- Windows 上
strftime(..., "%Y-%m-%dT%H:%M:%S%z")输出2024-05-20T13:45:30+0800—— 不符合 ISO 8601:2004 附录 B 要求 - 自己拼接时区字符串容易漏掉夏令时偏移或符号处理错误
std::put_time + std::gmtime 的安全写法
用 std::put_time 格式化 std::tm,再手动补上带冒号的时区。关键点:必须用 std::gmtime 获取 UTC 时间后反推本地偏移,避免 std::localtime 在多线程下非重入(C++20 前)。
- 先调用
std::gmtime(&t)得到 UTC 的std::tm - 用
std::mktime把它转回time_t,再和原值比较算出本地偏移秒数 - 偏移转为
+HH:MM字符串(注意负偏移、-05:30这类半时区) - 最后用
std::ostringstream拼接:YYYY-MM-DDTHH:MM:SS+ 时区
示例片段:
time_t t = std::time(nullptr);
std::tm utc_tm = *std::gmtime(&t);
std::time_t utc_as_local = std::mktime(&utc_tm); // 强制解释为本地时间
int offset_sec = static_cast<int>(t - utc_as_local);
char sign = offset_sec >= 0 ? '+' : '-';
int abs_off = std::abs(offset_sec);
int hh = abs_off / 3600;
int mm = (abs_off % 3600) / 60;
std::ostringstream oss;
oss <h3>C++20 <code><chrono></chrono></code> 的更简洁方案</h3>
<p>如果你能用 C++20,<code>std::chrono::zoned_time</code> + <code>std::format</code> 是最干净的:</p>
<ul>
<li>
<code>std::chrono::system_clock::from_time_t(t)</code> 转成 <code>sys_time</code>
</li>
<li>用 <code>std::chrono::current_zone()</code> 或指定时区构造 <code>zoned_time</code>
</li>
<li>
<code>std::format(std::locale{}, "{:%Y-%m-%dT%H:%M:%S%z}", zt)</code> 自动输出带冒号时区</li>
<li>注意:GCC 13+、Clang 16+、MSVC 19.35+ 才完整支持 <code>std::format</code> 和时区</li>
</ul>
<p>不支持 C++20 时,硬要省代码就用第三方库如 <code>date.h</code>(Howard Hinnant’s date library),它把 <code>std::format</code> 的能力提前带到了 C++11。</p>
<h3>容易被忽略的细节</h3>
<p>UTC 时间本身没有时区标识,但 ISO 8601 允许用 <code>Z</code> 表示零偏移。很多人直接用 <code>std::gmtime</code> + <code>std::put_time</code> 输出 <code>...Z</code>,却忘了:如果原始 <code>time_t</code> 来自网络协议(如 HTTP Date 头),它本就是 UTC,此时加 <code>Z</code> 正确;但如果想表达“本地时间按 ISO 格式转出”,就必须显式计算并插入本地偏移 —— 这个选择不能靠函数自动判断,得由业务逻辑决定。</p>
<p>另外,<code>std::tm</code> 的 <code>tm_isdst</code> 字段在 <code>std::gmtime</code> 中恒为 0,但在 <code>std::localtime</code> 中可能为 1,影响偏移计算。所以偏移必须通过时间戳差值算,不能依赖 <code>tm_gmtoff</code>(非标准字段,glibc 特有)。</p></int>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











