编译时间宏__date__和__time__是预处理阶段生成的固定字符串,非运行时值,不可直接用于时间计算或constexpr解析,需手动清洗并运行时解析才能转为时间类型。

编译时时间是预处理器概念,不是运行时值
编译时间(如 __DATE__ 和 __TIME__)在源码被预处理时就固化为字符串字面量,不会随程序启动或执行变化。这意味着你拿到的永远是「源文件被编译那一刻」的时间,且无法用 std::chrono 或 time_t 直接操作——它们是 C 风格字符串,不是时间类型。
__DATE__ 和 __TIME__ 的实际用法与限制
这两个宏展开为形如 "Jan 1 2024" 和 "14:32:17" 的字符串,空格数量固定(月份缩写占3字符,日期前补空格对齐),不能直接传给 std::get_time 或 strptime 而不先清洗。
- 月份名是英文缩写(
"Jan"、"Feb"),不随本地化环境改变 -
__DATE__中日份前可能有单个空格(如"Jan 5 2024"),需注意sscanf格式串中用%d仍能跳过多余空格 - 不能在 constexpr 上下文中直接解析成整数(C++20 前),因为宏展开结果不是字面量常量表达式
简单转成整数示例:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
constexpr auto build_date = __DATE__; // "Dec 25 2023" // 手动提取:month=12, day=25, year=2023(需自己写 constexpr 解析或用运行时 sscanf)
想存进结构体?得手动解析或接受字符串
如果目标是把编译时间塞进 struct tm 或 std::chrono::system_clock::time_point,必须走运行时解析。没有标准库函数能直接消费 __DATE__ 字符串。
- 推荐用
sscanf(C++11 起可用,且线程安全):sscanf(__DATE__, "%*s %d %d", &day, &year)——但月份需查表映射 - 避免用
std::istringstream+std::get_time,因为std::get_time依赖std::locale,而__DATE__固定为英文,locale 不匹配会导致解析失败 - 若只需日志或版本信息展示,直接拼接字符串最稳妥:
std::string build_info = std::string("Built on ") + __DATE__ + " at " + __TIME__;
跨平台和构建系统干扰项要当心
某些构建工具(如 CMake 的 configure_file、或 Ninja 在 rebuild 时重用对象文件)可能导致 __DATE__ 和 __TIME__ 滞后于真实编译时间。尤其在增量构建或 IDE 自动保存触发编译时,容易误判。
- Clang/GCC/MSVC 都支持这两个宏,行为一致;但 ICC 等小众编译器需查文档确认
- 使用
make -j并行编译时,多个源文件的__TIME__可能不同(取决于各自编译开始时刻) - 若需精确到秒级一致性,建议在 CMake 中生成一个头文件注入统一时间戳,而非依赖每个 .cpp 的宏
真正难的不是取时间,而是意识到:它不可靠、不可计算、不可移植解析——只适合打标签,别指望拿它做逻辑分支或时间差计算。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










