推荐用 std::chrono::system_clock::now() 获取纳秒级时间点,再通过 time_point_cast 截断精度或 to_time_t 转换后配合线程安全函数(localtime_s/localtime_r)和 std::put_time 格式化为本地时间字符串。

用 std::chrono 获取当前时间点(推荐)
C++11 起,std::chrono 是最可靠、类型安全的方式获取高精度时间点。它不直接提供“年月日”字符串,但返回的是一个与系统时钟对齐的纳秒级时间戳,后续可按需转换。
-
std::chrono::system_clock::now()返回time_point,代表自纪元以来的持续时间 - 若只需毫秒/微秒级精度,可用
std::chrono::time_point_cast截断,避免浮点误差 - 不要直接用
time_t构造system_clock::time_point,跨平台行为不一致(尤其 Windows) - 示例:获取当前毫秒时间戳(常用于性能打点)
auto now = std::chrono::time_point_cast<:chrono::milliseconds>( std::chrono::system_clock::now()); long long ms = now.time_since_epoch().count(); // 毫秒数 </:chrono::milliseconds>
用 std::put_time 格式化为本地时间字符串
要输出“2024-05-20 14:30:45”这类可读格式,必须经过 std::tm 中转,且注意时区陷阱。
- 先用
std::chrono::system_clock::to_time_t()转成time_t,再用localtime_r(Linux/macOS)或localtime_s(Windows)转std::tm - 直接调用
localtime()是线程不安全的,容易在多线程中返回错误结果 -
std::put_time的格式符和 C 的strftime一致,但必须配合std::ostringstream使用 - 示例:安全获取本地时间字符串
auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::tm tm_buf{}; #ifdef _WIN32 localtime_s(&tm_buf, &t); #else localtime_r(&t, &tm_buf); #endif std::ostringstream oss; oss
避免用 std::ctime 或 asctime
这两个函数看起来简单,但实际埋了多个雷:
- 返回的是静态缓冲区指针,多次调用会相互覆盖,多线程下必出错
- 输出固定格式(如
"Mon May 20 14:30:45 2024\n"),无法定制,末尾还带换行符 - 不区分时区,依赖全局环境变量
TZ,部署时容易因容器/服务器配置不同而错乱 - 已被 C++20 标记为 [[deprecated]],新项目应彻底避开
需要 UTC 时间?别用 gmtime 手动转
虽然 gmtime_r/gmtime_s 比 localtime 更“干净”,但它仍依赖系统时区数据库,且不能处理闰秒、历史时区变更等边界情况。
- 真正可靠的 UTC 字符串生成,应使用
std::chrono::utc_clock(C++20) - 若限于 C++17 及以下,建议用第三方库如
date.h(Howard Hinnant 提供),它把std::chrono和时区逻辑封装得足够健壮 - 自己手写
time_t → UTC tm转换极易出错,比如忽略夏令时规则或 POSIX 时区字符串解析差异
时区和精度是 C++ 时间处理里最容易被跳过的两层细节,尤其是 localtime_r 和 localtime_s 的参数顺序、缓冲区初始化、以及 std::tm 的 tm_isdst 字段是否被正确设置——这些地方一漏,测试通过但上线后某天就出错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











