__date__ 是编译时展开的字符串字面量,格式为"jan 01 2024",需用 const char* 接收,不可当函数调用;转 std::chrono::time_point 需手动解析,仅精确到日。

用 __DATE__ 宏直接获取编译时日期字符串
__DATE__ 是 C++ 标准预定义宏,由编译器在预处理阶段展开为形如 "Jan 01 2024" 的字符串字面量。它不依赖运行时、无开销、无需头文件,只要编译发生,值就固定。
常见误用是试图把它当变量或函数调用:__DATE__() 或 auto date = __DATE__; 虽然能编译(因为它是字符串字面量),但容易让人误解为可变值——它实际在每次编译时硬编码进二进制,哪怕源码没改、仅重链接也不会更新。
- 必须用
const char*接收,例如:const char* build_date = __DATE__; - 不能直接用于
std::string初始化而不加std::string(__DATE__)—— 因为__DATE__是const char[12]类型,隐式转换可能触发模板匹配歧义 - 月份缩写固定为英文大写三字母(
"Dec"不是"DEC"或"dec"),空格数固定:1 个空格分隔月与日,2 个空格分隔日与年(如"Dec 5 2024")
把 __DATE__ 转成 std::chrono::system_clock::time_point
如果需要参与时间计算(比如判断是否过期、算距今几天),得解析成标准时间类型。但注意:__DATE__ 没有时分秒和时区,只能精确到日;且 C++20 前无原生解析支持,需手动拆解。
安全做法是用 std::sscanf 配合已知格式(月份名映射为数字),避免依赖 locale:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
int y, m, d;
const char* date_str = __DATE__;
const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int month_idx = -1;
for (int i = 0; i
-
std::mktime会将tm视为本地时区,若需 UTC,请用_mkgmtime(MSVC)或timegm(POSIX),注意跨平台差异 - 不要用
std::get_time—— 它依赖当前 locale,而__DATE__总是英文格式,locale 切换会导致解析失败 - 月份字段可能有前导空格(如
"Jan 5"中的两个空格),sscanf("%d")自动跳过空白,但起始偏移要算准(date_str + 4是跳过 "Jan ")
为什么不用 __TIME__ 或构建系统注入?
__TIME__ 给的是编译时刻的时:分:秒(如 "14:23:05"),但它和 __DATE__ 独立刷新——若编译跨午夜,两者日期可能不一致;且它不含日期信息,无法单独构造完整时间点。
构建系统(CMake/Make)注入如 -DBUILD_DATE=\"$(date +%Y-%m-%d)\" 看似灵活,但引入额外依赖:要求构建环境有 date 命令、shell 解析正确、且 CMake 缓存不污染。而 __DATE__ 是编译器保证行为,GCC/Clang/MSVC 全支持,连裸机交叉编译都可用。
- CI 环境中,如果使用 ccache 或 sccache,
__DATE__仍反映**实际编译发生的时间**,不是缓存命中的时间 —— 这点比外部注入更可靠 - 某些静态分析工具会警告
__DATE__导致构建不重复(non-reproducible),若你追求 bit-exact 构建,就得禁用它并改用构建系统注入 - 嵌入式开发中,
__DATE__常用于生成固件版本字符串,但要注意 Flash 空间:字符串常量会占用 ROM,"Oct 12 2024"占 12 字节,比 4 字节整数开销大
调试时发现 __DATE__ 没更新?检查编译触发逻辑
最常被忽略的一点:__DATE__ 只在**目标文件重新编译**时更新。如果只是修改了头文件但未触发对应 .cpp 重编译(比如没加 #include 依赖、或构建系统跳过了),那旧的日期仍保留在目标文件里。
- 用
make -d或ninja -d explain查看该源文件是否真被重新编译 - 在源码里加个无关变更(如空行、注释),强制触发重编译,再验证
- 检查 IDE 设置:某些 IDE(如 VS)默认启用“最小重建”,可能跳过未显式标记为“始终编译”的文件
- 若用 unity build(单个大 .cpp 包含多个源),整个 unity 文件的
__DATE__都是同一时刻 —— 这是设计使然,不是 bug
日期宏看着简单,但它的值只在编译器真正吐出新目标文件那一刻才钉死;任何构建缓存、依赖管理或 IDE 集成的疏漏,都会让你看到“昨天”的日期。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










