mktime() 是 PHP 中将本地时区日期时间组件转换为 Unix 时间戳的函数,参数顺序为 hour/minute/second/month/day/year,支持溢出自动校正但自 PHP 8.1 起已废弃,推荐使用 DateTime 类或 strtotime()。

直接说结论: mktime() 现在不是首选,但没坏、还能用;它生成的是**本地时区**的 Unix 时间戳,参数顺序反直觉(hour, minute, second, month, day, year),且容易因省略参数或非法日期触发静默校正——你传 mktime(0,0,0,13,1,2026),它不会报错,而是自动转成 2027-01-01 00:00:00。
为什么 mktime 的参数顺序这么怪?
它沿用了 C 标准库 mktime(struct tm*) 的历史设计,PHP 把结构体字段展开成独立参数,但没按年月日重排。结果就是:month 在 day 前,year 在最后。写错顺序(比如把 year 放第三位)会导致时间完全错乱,而且很难一眼发现。
常见错误现象:
- 传
mktime(2026, 8, 31, 0, 0, 0)→ 实际解析为hour=2026,远超 23,结果变成几天后某个时间 - 漏掉
hour却写了minute→ 后面所有参数左移,minute被当hour用
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 永远显式写出全部 6 个参数,避免依赖默认值(尤其在跨时区服务器上)
- 用
date('Y-m-d H:i:s', $ts)验证输出,别只看数字戳 - 如果只是取“今天 0 点”,优先用
strtotime('today')或new DateTime('today')->getTimestamp(),语义更清晰
mktime 处理非法日期时会自动“修正”,这合理吗?
合理,但危险。它把 mktime(0,0,0,2,30,2026)(2026 年 2 月 30 日)转成 2026-03-02 00:00:00,逻辑是:2 月只有 28 天 → 多出 2 天 → 进到 3 月 2 日。这个行为叫“规范化”,和 DateTime 类一致。
问题在于:你本意可能是想捕获输入错误,但它默默修好了,还返回有效时间戳。调试时很难意识到日期被改过。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 需要严格校验时,先用
checkdate($month, $day, $year)判断合法性,再调mktime() - 批量处理用户输入的日期字符串时,改用
DateTime::createFromFormat(),它支持!Y-m-d模式(带!表示拒绝任何偏差) -
mktime(0,0,0,0,0,0)是合法调用,结果是 1969-12-31(因为 month=0 → 上一年 12 月),这种边界情况要特别注意
mktime 和 gmmktime 的核心区别在哪?
就一点:mktime() 解释你给的年月日为**当前服务器本地时区**的时间,gmmktime() 解释为**GMT/UTC** 时间。两者返回的数值通常差 8 小时(如东八区),且不受 date_default_timezone_set() 影响。
例如,在上海服务器上执行:
var_dump(mktime(0,0,0,8,31,2026)); // 返回 1788163200 → 对应 2026-08-31 00:00:00 CST var_dump(gmmktime(0,0,0,8,31,2026)); // 返回 1788192000 → 对应 2026-08-31 00:00:00 UTC
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 存时间戳到数据库时,统一用 UTC(推荐
gmmktime()或new DateTime('2026-08-31', new DateTimeZone('UTC'))->getTimestamp()) - 不要混用:比如用
mktime()生成时间戳,再用date('Y-m-d', $ts)输出,却忘了date()默认按本地时区格式化——结果看起来像“多了一天”或“少了一天” -
is_dst参数在 PHP 5.1+ 已废弃,传了也无效,删掉
现在还该用 mktime 吗?
能不用就不用。它的设计目标是“C 兼容 + 快速生成时间戳”,但现代 PHP 项目里,DateTime 类更安全、可读性更强,且天然支持时区、DST、格式化、加减运算。比如“本月第一天”:
// mktime 方式(易错、难维护)
$first = mktime(0,0,0,date('m'),1,date('Y'));
<p>// DateTime 方式(明确、不易错)
$first = (new DateTime('first day of this month'))->setTime(0,0,0)->getTimestamp();真正绕不开 mktime() 的场景只剩两个:老系统兼容、或极端性能敏感(微秒级差异)。其他时候,它只是个“能跑但不推荐”的遗留接口。最常被忽略的一点是:它不感知 DateTimeZone 对象,所有计算都绑定服务器环境——换台服务器,结果可能就变了。



















