最稳妥做法是用std::chrono::system_clock::time_point表示日期再计算差值,避免手动解析或儒略日;需设tm_isdst=-1防DST歧义,禁用difftime直接除86400。

用 std::chrono + std::tm 转换最稳妥
直接用 std::chrono::system_clock::time_point 表示日期,再转成日历时间计算差值,是 C++11 及以后推荐做法。关键在于避免手动解析字符串或手算儒略日——容易出错且不跨平台。
-
std::get_time从字符串读取到std::tm,注意tm_year要加 1900,tm_mon是 0–11 - 用
std::mktime将std::tm转为std::time_t(秒级时间戳),它会自动归一化非法字段(比如 2023-13-01 → 2024-01-01) - 两次转换后相减,除以
24 * 3600得整数天数;用std::chrono::duration_cast更精确
std::string s1 = "2023-05-15";
std::string s2 = "2023-06-20";
std::tm t1 = {}, t2 = {};
std::istringstream ss1(s1), ss2(s2);
ss1 >> std::get_time(&t1, "%Y-%m-%d");
ss2 >> std::get_time(&t2, "%Y-%m-%d");
t1.tm_year += 1900; t1.tm_mon -= 1;
t2.tm_year += 1900; t2.tm_mon -= 1;
auto tp1 = std::chrono::system_clock::from_time_t(std::mktime(&t1));
auto tp2 = std::chrono::system_clock::from_time_t(std::mktime(&t2));
auto days = std::chrono::duration_cast(tp2 - tp1).count(); 别信 std::difftime 直接除 86400 的结果
std::difftime 返回的是秒差,但直接除 86400 会因夏令时切换出错:某天可能只有 23 小时或 25 小时。例如 2023-11-05(美国 DST 结束日),mktime 生成的两个相邻午夜时间戳差值可能是 82800 秒(23 小时),此时除 86400 得 0 天,但实际是 1 日历日。
- 必须用
std::chrono::days这类日历感知类型做差值转换 - 如果输入不含时分秒,默认按本地时区当日 00:00:00 处理,
mktime会帮你对齐到午夜 - 跨年、跨闰年、跨时区偏移变化,都由
std::mktime和std::chrono::system_clock联合处理
纯整数计算(无标准库依赖)要自己实现儒略日转换
嵌入式或受限环境若不能用 或 ,就得手写儒略日(Julian Day Number)公式。这是唯一能稳定支持公元前日期、且不依赖系统时区的方案。
- Gregorian 历法下,日期
(Y, M, D)对应儒略日数公式为:JDN = (1461 * (Y + 4800 + (M - 14) / 12)) / 4 + (367 * (M - 2 - 12 * ((M - 14) / 12))) / 12 - (3 * ((Y + 4900 + (M - 14) / 12) / 100)) / 4 + D - 32075 - 月份
M用 1–12,年份Y可为负(公元前 1 年记作 0,公元前 2 年记作 -1) - 两日期间隔 =
JDN2 - JDN1,结果恒为整数天,无时区/夏令时干扰
常见错误:忽略 tm_isdst 导致本地时间歧义
用 std::mktime 前没设 tm_isdst = -1,会导致某些系统(如 glibc)把时间当作“已知非夏令时”处理,从而在 DST 切换窗口内算错一天。例如 2023-11-05 01:30 在美国东部时间重复出现两次,mktime 若未设 -1 可能固定选第一次,造成后续差值偏差。
立即学习“C++免费学习笔记(深入)”;
- 务必在填充
std::tm后加一句:t1.tm_isdst = t2.tm_isdst = -1; - 不要假设输入字符串带有时区信息——
std::get_time不解析时区,全靠本地时区解释 - 若需 UTC 时间,请用
std::timegm(POSIX)或 C++20 的std::chrono::utc_clock替代std::mktime
实际项目里,只要不是裸机或极端受限环境,优先走 std::chrono + std::mktime 路线。儒略日算法虽稳,但调试困难、易抄错常数;而忽略 tm_isdst 或乱除 86400 是线上服务最常踩的坑。











