最可靠方式是用 std::chrono::system_clock::now() 获取时间点,floor 到当天零点,再加减 std::chrono::days{1},转为 year_month_day 自动处理跨月闰年;纯日期用 days,带时间用 hours 但需注意夏令时。

用 std::chrono 加减一天最可靠
直接操作 tm 结构体手动加减日、月、年容易出错(比如跨月、闰年、时区),std::chrono 是 C++11 之后推荐方式,底层自动处理日历逻辑。核心思路是:获取当前系统时间点 → 转成本地日历日期 → 加减 1 天 → 格式化输出。
关键点在于必须用 std::chrono::system_clock::now() 获取时间点,再通过 std::chrono::floor<:chrono::days></:chrono::days> 截断到当天零点,否则毫秒级精度会导致加减后仍落在同一天(尤其在临界时刻)。
- 用
std::chrono::days{1}表示一天,不是std::chrono::hours{24}(后者不处理夏令时偏移) - 转换为
std::chrono::year_month_day后,用.year()、.month()、.day()成员函数提取整数 - 不要用
std::put_time直接格式化std::chrono::system_clock::time_point,它依赖std::tm,可能因时区导致偏差
跨月/跨年时 std::chrono::year_month_day 自动进位
比如今天是 2024-03-01,减一天得到 2024-02-29;今天是 2023-01-01,减一天得到 2022-12-31。这些都不需要手动判断月份天数或是否闰年——year_month_day 的构造函数内部已封装了完整日历算法。
但注意:它只处理“日历日期”,不带时分秒和时区信息。如果你需要带具体时间的昨天/明天(比如“2024-03-01 14:30:00 的昨天是 2024-02-29 14:30:00”),就得用 std::chrono::system_clock::time_point 加减 std::chrono::hours{24},但此时要小心夏令时切换日(可能变成 23 或 25 小时)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 纯日期需求(如日志归档、报表周期)→ 用
year_month_day+days{1} - 带时间戳的精确偏移(如定时任务触发)→ 用
system_clock::time_point+hours{24} - 永远别用
tm.tm_mday += 1然后mktime,它在某些 libc 实现中对负值或超界值行为未定义
Windows 下需链接 legacy_stdio_definitions.lib
Visual Studio 2015 及以后默认禁用旧式 C 运行时符号,而 std::chrono::year_month_day 的流输出(operator)依赖部分 legacy 符号。如果编译报错 <code>LNK2019: unresolved external symbol "class std::basic_ostream<char std::char_traits> > & __cdecl std::operator...</char>
- 在项目属性 → 链接器 → 输入 → 附加依赖项里加上
legacy_stdio_definitions.lib - 或者改用手动拼接:
os - Linux/macOS 无此问题,
libc++和libstdc++均完整支持
输出格式不一致?检查 std::locale 是否被意外修改
如果 std::cout 输出的是类似 <code>2024-3-1(缺前导零),大概率是当前全局 locale 的 std::time_put facet 没启用数字填充。这不是 bug,而是标准库按 locale 定义的格式输出。
- 临时解决:用
std::printf("%04d-%02d-%02d", ymd.year(), ymd.month(), ymd.day()); - 长期方案:在程序开头调用
std::ios_base::sync_with_stdio(false);并显式设置 locale:std::locale::global(std::locale("C")); - 避免在多线程环境中全局修改 locale,不同线程可能互相覆盖
日期计算本身没问题,但输出样式容易让人误以为结果错了——实际只是格式化环节没对齐预期。

















