使用std::chrono计算日期出现异常结果的原因探究
日历单位用错了场景
std::chrono里的years、months、days是日历专用的偏移单位,不是固定时长的时间戳偏移。比如要是从系统时间戳的起点(1970-01-01 UTC)直接累加years(2023),得到的是3993年,完全不是你要的2023年。正确姿势是先构造year_month_day{2023, 2, 28}这种日历日期,再转成时间点;而你用struct tm的时候是直接填年月日,自然不会犯这种方向性错误。时区处理没明确,导致混淆
std::chrono的system_clock时间点本质是UTC时间戳,但如果转日历日期时用了本地时区(比如current_zone()),就会把本地时间当成UTC来处理。比如你要的是UTC 17:00,用UTC+8时区的current_zone()转换2023-02-28 17:00,得到的时间戳其实对应UTC的09:00,结果自然不对。
而struct tm的方式,你大概率是手动调整了时区(比如把小时减8)或者用了timegm(而非mktime)来直接转UTC时间,避开了时区混淆的坑。日期合法性的处理逻辑不同
std::chrono的日历类型(比如year_month_day)是严格校验的,要是构造了非法日期(比如2023-02-29),转换时间点时要么报错要么出异常结果;但如果你累加月份时不小心越界(比如从2023-01-31加1个月得到2023-02-31,这是无效日期),也会出问题。
反观mktime,它会自动调整非法日期——比如你填了3月32日,它会自动转成4月1日,这种容错机制反而让你在不小心出错时得到了“正确”结果,而std::chrono的严格性反而暴露了你的操作错误。
内容的提问来源于stack exchange,提问作者barbyQAQ

