最稳妥的时间戳拼接方案是用 std::chrono 配合 std::put_time:先将 system_clock::now() 转为 time_t,再用线程安全的 localtime_r(Linux/macOS)或 _localtime64_s(Windows)转为 tm,最后用 std::put_time 格式化;毫秒需手动提取并补零;硬编码 "%Y-%m-%d %H:%M:%S" 格式以保证跨平台解析一致性。

用 std::chrono + std::put_time 拼接时间戳最稳妥
直接调用系统命令(比如 date)或手撕字符串格式化,容易出时区、精度、线程安全问题。C++11 起 std::chrono 配合 std::put_time 是标准、可移植、线程安全的方案。
关键点:必须先把 system_clock::now() 转成 std::time_t,再用 std::put_time 格式化;不能直接对 duration 做流输出。
-
std::put_time只接受std::tm*,得用std::localtime或std::gmtime转换(注意线程安全:用std::localtime_r/std::gmtime_r更好) - 常见错误是漏掉
头文件,导致编译报error: 'put_time' is not a member of 'std' - 如果只要秒级精度,
system_clock::to_time_t足够;要毫秒级,得手动拆解time_since_epoch()
#include <chrono>
#include <ctime>
#include <iomanip>
#include <fstream>
#include <sstream>
std::string get_timestamp() {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
auto ms = std::chrono::duration_cast<:chrono::milliseconds>(now.time_since_epoch()) % 1000;
std::stringstream ss;
ss <h3>写入性能敏感时别在每次写都调用 <code>get_timestamp()</code>
</h3>
<p>高频日志场景下,反复构造 <code>std::stringstream</code>、调用 <code>std::localtime</code>、格式化字符串,开销明显。不是所有“加时间戳”都需要毫秒级实时性。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>每秒只更新一次时间戳缓存,误差 ≤1s,但吞吐能提升 3–5 倍(实测 clang++15 + O2)</li>
<li>用 <code>static std::string cached_ts</code> + <code>static std::time_t last_update</code> 双检查,避免锁</li>
<li>注意:多线程下 <code>std::localtime</code> 返回静态缓冲区,必须用 <code>std::localtime_r</code> 替代,否则可能输出错乱时间</li>
<li>如果日志量极低(比如配置加载、启动记录),直接每次调用更简单,不必过早优化</li>
</ul>
<h3>Windows 下 <code>std::localtime_r</code> 不存在?用 <code>_localtime64_s</code> 替代</h3>
<p>MSVC 不支持 POSIX 的 <code>_r</code> 版本函数,直接编译会报 <code>error C3861: 'localtime_r': identifier not found</code>。</p>
<ul>
<li>Windows 必须用 <code>_localtime64_s</code>(支持 64 位 time_t)或 <code>localtime_s</code>(旧版)</li>
<li>记得加 <code>#define _CRT_SECURE_NO_WARNINGS</code> 或改用安全版本,否则 VS 默认禁用 <code>localtime</code>
</li>
<li>跨平台宏封装建议:用 <code>#ifdef _WIN32</code> 分支,Linux/macOS 走 <code>localtime_r</code>,Windows 走 <code>_localtime64_s</code>
</li>
<li>别用 <code>ftime()</code>:已废弃,精度差,且 Windows 上返回的是 UTC,不是本地时间</li>
</ul>
<h3>时间戳格式不一致?统一用 <code>%Y-%m-%d %H:%M:%S</code> 开头</h3>
<p>不同 locale 下 <code>%x</code> 或 <code>%X</code> 表现不一致(比如德语系统输出 “23.04.2024”),grep、logrotate、ELK 解析全崩。硬编码格式最可靠。</p>
<ul>
<li>
<code>%Y</code>(4 位年)比 <code>%y</code> 安全,避免 2038 年问题混淆</li>
<li>
<code>%H:%M:%S</code> 是 24 小时制,无歧义;别用 <code>%I:%M:%S %p</code>(AM/PM 在日志里反而难排序)</li>
<li>毫秒补零必须用 <code>std::setfill('0') + std::setw(3)</code>,否则 <code>12:34:56.7</code> 这种格式无法对齐,影响文本分析</li>
<li>如果后续要被 Python <code>datetime.fromisoformat()</code> 直接解析,建议用 ISO 8601: <code>"%Y-%m-%dT%H:%M:%S"</code>(注意 T 是字面量)</li>
</ul>
<p>
时间戳看着简单,真正上线后卡在 Windows 线程安全、locale 解析失败、毫秒补零错位上的情况,比想象中多得多。动手前先确认目标平台和日志消费方怎么解析——有时候少一个 <code>std::setfill('0')</code>,整条 pipeline 就停了。</p></:chrono::milliseconds></sstream></fstream></iomanip></ctime></chrono>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










