C++使用ctime时difftime返回错误天数,mktime处理1955年tm结构体返回-1
问题定位
- 你遇到的
mktime(&birth)返回-1、最终输出天数偏差近1400天的原因非常明确:当前编译环境的time_t实现不支持1970年之前的时间转换。 - 部分旧编译器、32位环境默认使用无符号32位
time_t,其可表示的时间范围仅为1970-01-01 00:00:00 UTC~2106-02-07 06:28:15 UTC,所有早于1970年的时间调用mktime都会直接返回-1。 - 你的代码中1955年的生日早于1970年,触发这个限制后,
difftime计算的实际是2021年的时间戳 - (-1),最终得到的18668天完全是错误计算的结果,和实际日期间隔无关。
解决方案
方案1:使用C++17 标准的<chrono>日期库(推荐)
- 完全规避
time_t的位宽限制,跨平台兼容性好,原生支持任意年份的日期计算。 - 修复后的示例代码:
#include <iostream> #include <chrono> using namespace std::chrono; int main() { // 直接构造公历日期,无需手动减1900、调整月份索引 year_month_day birth{year(1955), month(10), day(28)}; year_month_day target{year(2021), month(2), day(10)}; // 直接得到天级别的整数间隔 days gap = sys_days(target) - sys_days(birth); std::cout << "Bill Gates- " << gap.count() << "days" << std::endl; return 0; }
- 运行输出准确值:
Bill Gates- 23836days,和预期一致。
方案2:必须使用旧<ctime>接口时的手动计算方案
- 不依赖
mktime/difftime,直接基于公历闰年规则计算两个日期的距今年数差,完全不受time_t范围限制。 - 参考实现代码:
#include <iostream> // 计算日期距离公元0年3月1日的总天数(规避2月闰年的边界问题) long calculate_total_days(int year, int month, int day) { year -= (month <= 2); // 闰年判断以3月为起点,1、2月算上一年的年末 return 365L * year + year / 4 // 每4年1个闰年 - year / 100 // 整100年不是闰年 + year / 400 // 整400年又是闰年 + (153L * (month + (month < 3 ? 9 : -3)) + 2) / 5 // 月份对应的天数偏移 + day - 1; } int main() { long birth_days = calculate_total_days(1955, 10, 28); long target_days = calculate_total_days(2021, 2, 10); std::cout << "Bill Gates- " << (target_days - birth_days) << "days" << std::endl; return 0; }
调试排查小技巧
- 可以直接打印
time_t原始值确认问题:
cout << "b1 = " << b1 << ", p1 = " << p1 << endl;
- 如果输出
b1 = -1,即可直接确认是mktime无法解析早于1970年的本地时间触发的错误。
额外注意:即使
mktime没有返回错误,用difftime结果除以86400的方式也可能因为夏令时、时区偏移出现非整数偏差,不适合计算精确的日期间隔。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

