最可靠方法是用 std::chrono::sys_days(c++20)将日期转为自1970-01-01起的整数天数再相减,避免闰年、时区、夏令时等陷阱;旧标准需用 std::tm + std::mktime 并设 tm_isdst = -1,或借助第三方库。

用 std::chrono 转换时间点再相减最可靠
直接用年月日手动算天数会掉进闰年、时区、夏令时、历法变更(比如1582年10月跳过10天)的坑里,std::chrono 底层调用系统时钟或日历库,能规避大部分陷阱。关键不是“自己写逻辑”,而是把日期转成 std::chrono::system_clock::time_point,再相减得到 duration,最后除以 24h 得浮点天数。
注意:C++20 之前不支持直接解析 "2023-05-12" 这种字符串,得先用 std::get_time 或第三方库(如 Howard Hinnant 的 date 库);C++20 起可用 std::chrono::year_month_day + sys_days,但需确认编译器支持(GCC 12+ / Clang 14+)。
- 推荐用 C++20 的
std::chrono::sys_days:它把日期归一为自 1970-01-01 起的整数天数,再转成time_point,精度高且无歧义 - 若只能用 C++11/14/17,老老实实用
std::tm+std::mktime,但注意std::mktime会按本地时区解释输入,跨时区计算结果不准 - 所有方法都默认按公历(Gregorian calendar)处理,不支持儒略历等历史历法
std::chrono::sys_days 计算示例(C++20)
这是目前最干净的方式,不依赖本地时区,也不需要手动处理闰秒(sys_days 不含秒级精度,天然规避闰秒影响):
#include <chrono>
#include <iostream><p>int main() {
using namespace std::chrono;
auto d1 = sys_days{year{2023}/May/12};
auto d2 = sys_days{year{2024}/Jan/1};
auto diff = d2 - d1; // 类型是 days
double days_float = static_cast<double>(diff.count());
std::cout </double></p>
<p>如果真要“精确到小数点后”,比如带小时分钟,就得升一级到 <code>time_point</code>:</p>
<pre class="brush:php;toolbar:false;">auto tp1 = d1 + 12h + 30min;
auto tp2 = d2 + 8h + 15min;
auto diff_sec = tp2 - tp1; // duration<double seconds::period>
double exact_days = diff_sec.count() / (24.0 * 3600.0);</double>
这里 24.0 * 3600.0 是显式转成浮点除法,避免整数截断。
用 std::mktime 的常见错误和补救
很多人写:
std::tm t1 = {}, t2 = {};
t1.tm_year = 2023-1900; t1.tm_mon = 4; t1.tm_mday = 12;
t2.tm_year = 2024-1900; t2.tm_mon = 0; t2.tm_mday = 1;
auto sec1 = std::mktime(&t1);
auto sec2 = std::mktime(&t2);
问题在于:std::mktime 把输入当成本地时间,如果机器时区是 UTC+8,那 2023-05-12 00:00 就被当成 UTC+8 的午夜,对应 UTC 是 2023-05-11 16:00 —— 两个日期差可能多出或少掉一天。
- 必须在调用前设
t1.tm_isdst = t2.tm_isdst = -1,让系统自动判断夏令时,否则可能错算一小时 - 若需 UTC 时间,改用
std::timegm(POSIX)或 C++20 的utc_clock,但timegm非标准,Windows 不支持 - 哪怕同在一个时区,
std::mktime对 1970 年前的日期行为未定义,某些 libc 会返回 -1
为什么不用 double 直接存“年份小数”来算
有人想把 2023-05-12 换算成 2023.366(12/365 ≈ 0.033),再相减——这完全不可靠。
原因很实在:2023.366 和 2024.003 相减得 0.637 年,乘以 365.2425 ≈ 232.7 天,但真实天数是 234 天。误差来自:每年天数不固定(365 或 366)、月份天数不均、小数近似累积偏差。这种算法在跨年、跨闰年时误差会扩大到 ±2 天以上。
真正需要浮点天数的场景(比如财务利息、科学计算),必须基于真实时间轴上的连续秒数或天数,而不是日历年的线性插值。
最易被忽略的一点:即使你只关心“日历天数”(不计小时),sys_days 给出的是完整天数,而“两个日期之间的天数”在业务上常指“间隔天数”,即 d2 - d1,不是“包含多少个 24 小时周期”。这点必须跟需求方对齐,代码没法替你决定语义。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











