必须清零 struct tm 才能用 mktime,否则未初始化字段(如 tm_hour、tm_min、tm_sec、tm_isdst)会导致计算结果严重偏差;推荐用 struct tm tm = {}; 或 memset(&tm, 0, sizeof(tm)) 清零,并正确设置 tm_year(年份减1900)、tm_mon(0~11)、tm_isdst(建议设0)。

为什么必须清零 struct tm 才能用 mktime
不主动清零 struct tm,mktime() 会拿栈上未初始化的随机值(尤其是 tm_hour、tm_min、tm_sec、tm_isdst)参与计算,结果可能偏差几十年——比如输入 2024-01-01 却算出 1952-06-17。这不是 bug,是 C 标准明确允许的未定义行为。
推荐两种清零方式:声明时初始化 or memset
二者都有效,但适用场景不同:
-
struct tm tm1 = {};—— 最简洁,适用于声明即用的场景;C++11 起支持,自动零初始化所有字段(包括 padding 字节) -
memset(&tm2, 0, sizeof(tm2));—— 适用于已声明变量后续重用,或需在函数中间清空;注意必须传&tm2和sizeof(tm2),不能传错指针或字节数
别写 struct tm tm = {0}; —— 这在 C 里合法,在 C++ 中虽多数编译器接受,但严格来说只初始化第一个成员,其余未明确定义;{} 才是跨语言安全写法。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
容易漏掉的关键字段:tm_year 和 tm_mon
清零只是第一步,填值时仍要遵守规则:
-
tm_year填的是「年份减 1900」,例如 2024 年 →tm.tm_year = 124; -
tm_mon是 0~11,1 月为 0,12 月为 11,别直接填 1~12 -
tm_mday是 1~31,注意各月天数及闰年;超出范围会导致mktime()归一化(可能跳月),但非预期行为 - 即使只算日期,也显式设
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;,比依赖清零更直观、可读
tm_isdst 设 0 还是 -1?
tm_isdst 控制夏令时推断逻辑:
- 设为
-1(默认):mktime()尝试根据系统时区和日期自动判断,但在 DST 切换日(如 3 月第二个周日)可能失败,返回-1 - 设为
0:强制禁用夏令时,结果稳定,适合大多数日期差计算场景 - 设为
1:强制启用,极少需要
建议统一设 tm.tm_isdst = 0;,除非业务明确要求考虑夏令时偏移。
tm_year 和 tm_mon 的偏移量、tm_isdst 的语义,漏一个就可能导致时间差算错好几天,而且这种错误在测试中还不容易暴露。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










