最稳妥做法是用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–11std::mktime 将 std::tm 转为 std::time_t(秒级时间戳),它会自动归一化非法字段(比如 2025-13-01 → 2025-01-01)
24 * 3600 得整数天数;用 std::chrono::duration_cast 更精确std::string s1 = "2025-05-15";
std::string s2 = "2025-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 小时。例如 2025-11-05(美国 DST 结束日),mktime 生成的两个相邻午夜时间戳差值可能是 82800 秒(23 小时),此时除 86400 得 0 天,但实际是 1 日历日。
std::chrono::days 这类日历感知类型做差值转换mktime 会帮你对齐到午夜std::mktime 和 std::chrono::system_clock 联合处理嵌入式或受限环境若不能用 或 ,就得手写儒略日(Julian Day Number)公式。这是唯一能稳定支持公元前日期、且不依赖系统时区的方案。
(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 切换窗口内算错一天。例如 2025-11-05 01:30 在美国东部时间重复出现两次,mktime 若未设 -1 可能固定选第一次,造成后续差值偏差。
立即学习“C++免费学习笔记(深入)”;
std::tm 后加一句:t1.tm_isdst = t2.tm_isdst = -1;
std::get_time 不解析时区,全靠本地时区解释std::timegm(POSIX)或 C++20 的 std::chrono::utc_clock 替代 std::mktime
实际项目里,只要不是裸机或极端受限环境,优先走 std::chrono + std::mktime 路线。儒略日算法虽稳,但调试困难、易抄错常数;而忽略 tm_isdst 或乱除 86400 是线上服务最常踩的坑。