std::chrono::system_clock::now() 获取当前时间点,需转 time_t 再用 localtime_r/s 拆解为 std::tm,注意时区、线程安全及 tm 字段偏移(如 tm_mon 从 0 开始),格式化推荐 std::put_time 配合 "C" locale。

用 std::chrono::system_clock 获取当前时间点
C++ 标准库没有 DateTime.Now 这种带封装的类型,但 std::chrono::system_clock 是最接近的底层支撑——它对应系统本地时钟(通常就是墙上时间),精度足够、可移植、无需第三方依赖。
关键不是“构造一个对象”,而是理解它的返回值是时间点(time_point),不是字符串或结构体。常见错误是直接拿 time_point 去格式化,结果编译失败或输出乱码。
-
auto now = std::chrono::system_clock::now();得到的是纳秒/微秒级精度的time_point,类型取决于平台实现 - 若要转成 C 风格的
std::time_t(比如传给std::localtime),必须显式调用.time_since_epoch().count()或更安全的std::chrono::system_clock::to_time_t(now) - 注意:
system_clock不保证是本地时区——to_time_t返回的是 UTC 时间戳,std::localtime才做时区转换
转成年月日时分秒结构体(类似 DateTime.Date)
想拿到类似 C# 里 Now.Year、Now.Month 这样的字段,得走 std::tm 这条路,但步骤比 C# 多一跳:先转 time_t,再用 localtime_s(Windows)或 localtime_r(POSIX)线程安全地拆解。
容易踩的坑是直接用 std::localtime(&t)——它返回静态缓冲区指针,多线程下会互相覆盖;还有人忽略 tm_mon 是从 0 开始(1 月 = 0),tm_year 是距 1900 年的偏移(2024 年 = 124)。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- Windows 下推荐:
localtime_s(&tm, &t),&tm是你自己的std::tm变量地址 - Linux/macOS 下用:
localtime_r(&t, &tm),同样传入栈上变量地址 - 拿到
tm后,tm.tm_year + 1900是年份,tm.tm_mon + 1是月份,tm.tm_mday是几号
格式化为字符串(类似 Now.ToString("yyyy-MM-dd HH:mm:ss"))
C++20 引入了 std::format,但目前主流编译器(GCC 13/Clang 16 以下)支持不全;更稳的方式还是用 std::put_time 配合 std::ostringstream,但要注意 locale 设置。
默认 locale 可能导致月份名变成英文以外的语言,或者格式符(如 %Y)被忽略——这是因为 std::put_time 依赖 facet,而默认流没绑定 std::time_put facet。
- 安全写法:
oss.imbue(std::locale("C"));再调用std::put_time(&tm, "%Y-%m-%d %H:%M:%S") - Windows 上如果用
"C"locale 报错,可试"en_US.UTF-8"或""(系统默认) - 格式符大小写敏感:
%H是 24 小时制,%I是 12 小时制;%S是秒,%s是 Unix 时间戳(别混)
封装一个轻量 DateTime 类(避免每次重复写三步)
真正在项目里频繁用,每次都写 system_clock::now() → to_time_t → localtime_r → put_time 太啰嗦。可以封装一个只读结构体,内部缓存 std::tm 和原始 time_point,但别试图模拟 C# 的全部行为(比如时区切换、加减运算)——那该交给 date.h 或 Boost.DateTime。
重点控制两点:一是构造函数必须私有或 explicit,防止误传时间戳;二是所有 getter(year()、hour())都基于同一份 std::tm,避免多次调用 localtime_r 导致秒数不一致(跨秒时可能取到不同分钟)。
- 示例骨架:
struct DateTime { DateTime() { /* 一次性完成 now → tm */ } int year() const { return tm_.tm_year + 1900; } int month() const { return tm_.tm_mon + 1; } private: std::chrono::system_clock::time_point tp_; std::tm tm_; }; - 别在类里存
std::string格式化结果——除非明确需要缓存,否则每次调用toString()重新格式化更省内存 - 如果需要毫秒级时间戳(比如日志打点),直接暴露
tp_.time_since_epoch().count(),别绕一圈转time_t
时区是最大陷阱:C++ 标准库至今没原生时区支持,system_clock 是 UTC,localtime 依赖系统时区设置。如果部署环境时区没配对,DateTime.Now 就会错一小时甚至更多——这点比 C# 更隐蔽,因为 C# 默认用系统时区且封装层做了适配。

















