推荐用 std::chrono::system_clock::now() 获取时间,转为 std::time_t 后配合 std::localtime 与 std::put_time 格式化输出,避免 strftime 的线程不安全和缓冲区溢出风险;注意时区、格式符含义及 C++20 时区支持尚不成熟。

用 std::chrono + std::put_time 最简洁安全
现代 C++(C++11 起)推荐用 std::chrono 获取系统时间,再用 std::put_time 格式化输出,避免 C 风格 strftime 的线程不安全和缓冲区溢出风险。
关键点:
-
std::chrono::system_clock::now()获取当前时间点 - 需转换为
std::time_t(用.time_since_epoch().count()不行,必须用std::chrono::system_clock::to_time_t) -
std::put_time需配合std::localtime或std::gmtime使用,注意它们返回的是静态缓冲区指针,多线程下要加锁或改用localtime_r/gmtime_r(POSIX)
示例(本地时间):
#include#include #include #include int main() { auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::cout << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S") << '\n'; }
strftime 仍可用,但必须手动管理缓冲区
如果你坚持用 C 风格 strftime(比如要兼容旧代码、或需要更细粒度控制),务必注意:strftime 不自己分配内存,你得提供足够大的字符数组,否则会截断甚至越界。
立即学习“C++免费学习笔记(深入)”;
常见错误:
- 传入太小的缓冲区(如
char buf[10]却格式化带年月日时分秒的字符串) - 忽略返回值:成功时返回实际写入长度(不含
\0),0 表示缓冲区不够或格式非法 - 误用
std::string::c_str()作为输出目标(只读,且生命周期不对)
正确写法示例:
#include#include #include int main() { std::time_t t = std::time(nullptr); struct std::tm* tm_info = std::localtime(&t); char buf[64]; if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm_info) == 0) { std::cerr << "strftime failed\n"; return 1; } std::cout << buf << '\n'; }
%Y、%y、%m 等格式符含义别记混
格式化字符串里最常出错的是年份和月份:
-
%Y→ 4 位年份(如2024),%y→ 2 位年份(24),不是%YY或%yyyy -
%m→ 01–12 的月份数字,%b→ 英文缩写(Jan),%B→ 全称(January) -
%d→ 当月第几天(01–31),%j→ 当年第几天(001–366) -
%H→ 24 小时制(00–23),%I→ 12 小时制(01–12),别漏了%p(AM/PM)
调试时可先用 "%Y-%m-%d %H:%M:%S" 验证基础逻辑,再逐步加其他字段。
时区问题:本地时间 vs UTC 很容易被忽略
默认 std::localtime 和 std::strftime(..., tm_info) 都依赖系统时区设置。如果程序部署在服务器上,而服务器时区是 UTC,但你要打印东八区时间,结果就差 8 小时。
解决办法有限:
- Linux/macOS 可临时设环境变量:
setenv("TZ", "Asia/Shanghai", 1); tzset();,再调localtime(注意:非线程安全) - C++20 引入了
的时区支持(zoned_time),但目前主流编译器支持还不稳定 - 最稳妥仍是用 UTC 时间(
std::gmtime)+ 手动加偏移,或交由前端/日志系统统一处理时区
别指望 strftime 自动识别时区缩写(如 %Z 输出可能为空或不准确),它只是照搬 tm 结构体里的字段。











