strtotime() 遇到非法字符串静默返回 false,PHP 7.0+ 中可能被转为 0(1970-01-01),需显式检查 === false;推荐用 DateTime::createFromFormat() 严格校验并结合 trim、str_replace 预处理及显式时区控制。

strtotime() 遇到非法字符串会返回什么
strtotime() 是 PHP 最常用的时间解析函数,但它对非法输入极其“宽容”——遇到无法识别的字符串(比如 "2024-02-30"、"abc"、空格或全角字符),它不会报错,而是静默返回 false。更危险的是,在 PHP 7.0+ 中,如果上下文允许类型转换(比如参与算术运算),false 会被转成 0,最终变成 Unix 时间戳 0(即 1970-01-01 00:00:00 UTC),这个结果看起来“合法”,却完全失真。
所以不能只靠 strtotime() 的返回值是否为整数来判断成功;必须显式检查是否为 false:
if (($ts = strtotime($input)) === false) {
throw new InvalidArgumentException("Invalid time string: '$input'");
}
用 DateTime::createFromFormat() 做严格格式校验
当输入格式已知(如固定为 "Y-m-d H:i:s" 或 "m/d/Y"),DateTime::createFromFormat() 比 strtotime() 更可靠。它不会猜测,只按指定格式匹配,且能通过 DateTime::getLastErrors() 暴露解析细节。
关键点:
立即学习“PHP免费学习笔记(深入)”;
- 即使部分匹配成功(如
"2024-02-30 10:00:00"中年月日格式对但日期非法),它也返回false - 必须检查返回值是否为
false,不能只看getLastErrors() - 建议配合
date_format()反向验证:解析后再格式化一次,看是否与原字符串一致(防多余空格、零填充等隐性不一致)
示例:
$dt = DateTime::createFromFormat('Y-m-d', $input);
$errors = DateTime::getLastErrors();
if ($dt === false || !empty($errors['warning_count'])) {
// 视业务决定是否接受警告(如忽略时分秒缺失)
}
常见非法字符串及预处理建议
真实业务中,非法输入往往不是乱码,而是格式松散或含干扰字符:
-
"2024/02/30 "(末尾空格)→ 用trim()清理 -
"2024年02月30日"(中文分隔符)→ 用str_replace()统一替换为-或/ -
"2024-02-30T10:00:00Z"(ISO 8601 格式但时区非法)→ 先用DateTimeZone::listIdentifiers()校验时区名,或直接用new DateTime($input)(它对 ISO 格式更健壮) -
"12/32/2023"(月日颠倒风险)→ 不要盲目互换,应结合业务上下文(如地区习惯)或要求明确格式
时区和夏令时引发的“合法但错误”问题
时间字符串本身合法(如 "2023-10-29 02:30:00"),但在某些时区(如 Europe/Berlin)可能对应夏令时切换时刻——该时间在本地时钟上“重复出现”或“根本不存在”。strtotime() 和 DateTime 默认按系统时区处理,容易忽略这一层语义。
应对方式:
- 始终显式指定时区:用
new DateTime($input, new DateTimeZone('UTC'))或DateTime::createFromFormat($fmt, $input, new DateTimeZone('Asia/Shanghai')) - 对关键业务(如预约、计费),解析后调用
$dt->getTimezone()->getOffset($dt)确认偏移量是否符合预期 - 避免依赖
date_default_timezone_set()全局设置,它易被其他代码覆盖
最易被忽略的一点:即使字符串格式正确、无语法错误、时区明确,夏令时边界值仍可能导致逻辑歧义——这不是解析失败,而是业务含义模糊,需要在解析后额外做合理性校验(例如检查是否落在 DST 跳变窗口内)。



















