最安全做法是用c++20的std::chrono::sys_days配合year_month_day:先floor到当日零点,再加days,最后转为年月日字段输出;c++17及更早需用mktime归一化tm结构并注意时区陷阱。

用 std::chrono 加天数最安全
直接对 std::chrono::system_clock::time_point 加 std::chrono::days(100) 是标准且跨平台的做法,避免手算月份天数、闰年、时区偏移等陷阱。C++20 起 <chrono></chrono> 原生支持日历运算,比旧式 tm + mktime 稳定得多。
关键点:
- 必须用
std::chrono::sys_days作为日期中间类型,它把时间点对齐到“午夜 UTC”,才能正确加减天数 - 不能直接对
time_point加days后再转tm——可能因本地时区导致日期偏差一天 - 起始日期建议用
std::chrono::floor<:chrono::days>(tp)</:chrono::days>截断到当日零点,否则毫秒级偏移可能影响结果
#include <chrono>
#include <iostream><p>auto today = std::chrono::floor<:chrono::days>(
std::chrono::system_clock::now()
);
auto later = today + std::chrono::days{100};
std::cout </:chrono::days></p>
<h3>输出为 YYYY-MM-DD 格式要过一道转换</h3>
<p><code>sys_days</code> 本身不提供格式化,得转成 <code>year_month_day</code> 再提取字段。C++20 的 <code><format></format></code> 尚未被所有编译器(如 GCC 12 默认)完全支持,稳妥做法是手动拼接。</p>
<p>常见错误:</p>
<ul>
<li>误用 <code>std::chrono::year_month_day{today}</code>:构造函数接受的是 <code>sys_days</code>,不是任意 <code>time_point</code>
</li>
<li>忽略 <code>year()</code> 返回的是 <code>std::chrono::year</code> 类型,需调 <code>.operator int()</code> 或 <code>.value()</code> 才能打印</li>
<li>月份和日直接用 <code>month().operator unsigned()</code>,但更推荐 <code>unsigned{md.month()}</code> 避免隐式转换警告</li>
</ul>
<pre class="brush:php;toolbar:false;">auto ymd = std::chrono::year_month_day{later};
std::cout <h3>兼容 C++17 及更早版本怎么办</h3><p>没有 <code>std::chrono::days</code> 和 <code>year_month_day</code>?别硬套 C++20 接口。老办法是用 <code>std::tm</code> + <code>mktime</code>,但必须注意:加 100 天后要重新归一化,否则 <code>tm_mday</code> 超出范围会导致 <code>mktime</code> 自动进位(这是正确行为,但容易误以为出错)。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>实操要点:</p>
- 初始化
tm时设tm_isdst = -1,让系统自动判断夏令时 - 加天数后必须调一次
mktime,它会修正tm_mon、tm_year等字段 - 第二次调
mktime(可选)能处理某些 libc 对首次归一化不彻底的问题,尤其在跨年边界 - 别依赖
tm_wday或tm_yday的初始值——它们在mktime前是未定义的
std::tm t = {};
t.tm_year = 2024 - 1900;
t.tm_mon = 5;
t.tm_mday = 15;
t.tm_hour = 0;
t.tm_isdst = -1;
auto time = mktime(&t);
t.tm_mday += 100;
mktime(&t); // 第一次归一化
mktime(&t); // 保险起见再归一化一次
别忽略时区和夏令时的隐性影响
哪怕你只关心“日期”,system_clock::now() 返回的是 UTC 时间点,而 mktime 解释 tm 时按本地时区处理。如果你在 UTC+8 时区执行 mktime,它会把传入的“2024-06-15 00:00:00”当成本地时间,再转成 UTC 时间戳——这可能导致计算出的“100 天后”在 UTC 时间上差出若干小时,进而影响 year_month_day 判断。
规避方式:
- 全程用
sys_days(C++20)——它基于 UTC 日历,无时区歧义 - 若用
tm,统一用timegm(非标准但广泛支持)替代mktime,它把tm当作 UTC 时间解析 - 绝对不要混用:比如用
localtime解析今天,再用gmtime输出结果
真正麻烦的不是算不准,而是不同机器、不同时区、不同 libc 实现下结果不一致——这点在自动化脚本或服务端逻辑里最容易暴露。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










