
strtotime() 转日期失败的常见原因
直接用 strtotime() 解析字符串,结果返回 false 或错误时间,多半是格式不匹配或时区干扰。它只认有限几种常见格式(如 "2024-03-15"、"15 March 2024"、"2024/03/15 14:30:00"),遇到 "15-03-2024" 或 "2024.03.15" 就可能出错。
- 默认按系统时区解析,如果没设时区,
date_default_timezone_set('Asia/Shanghai')必须提前调用,否则strtotime("now")都可能偏差 - 含中文或非标准分隔符(如顿号、空格不一致)时,基本不可靠
- 年份两位数(如
"23-03-15")会被当成 1923 年,不是 2023 年
DateTime::createFromFormat() 更可控的替代方案
当你明确知道字符串格式,比如日志里固定是 "Y/m/d H:i:s" 或数据库导出的 "d-m-Y",DateTime::createFromFormat() 是更稳的选择——它不猜,只按你给的模板硬匹配。
- 第一个参数是格式字符串(注意大小写:
"Y"是 4 位年,"y"是 2 位;"d"是带前导零的日,"j"是无前导零的 - 第二个参数是待解析的字符串,必须严格对齐格式,多一个空格、少一个冒号都会返回
false - 建议配合
get_last_errors()检查解析失败原因:DateTime::getLastErrors()返回数组,看['warning_count']和['warnings']
示例:$date = DateTime::createFromFormat('d-m-Y', '15-03-2024'); → 成功;DateTime::createFromFormat('Y-m-d', '15-03-2024') → 失败
从 MySQL 时间戳字符串转 DateTime 对象要注意什么
MySQL 的 DATETIME 字段值(如 "2024-03-15 14:22:07")可以直接传给 new DateTime(),但别依赖这个“巧合”。它能工作,是因为该格式恰好是 ISO 8601 子集,PHP 内部用类似 strtotime() 的逻辑处理。
立即学习“PHP免费学习笔记(深入)”;
- 如果字段是
TIMESTAMP类型且存的是 UTC 时间,而你的脚本时区是Asia/Shanghai,new DateTime($mysql_time)会自动转成本地时区时间,可能和原始值语义不符 - 更安全的做法是显式指定时区:
new DateTime($mysql_time, new DateTimeZone('UTC')),再用setTimezone()转目标时区 - 避免把
UNIX_TIMESTAMP()的整数结果直接丢给new DateTime()—— 它会当成字符串解析,不是时间戳。要用DateTime::setTimestamp()或date_create('@'.$ts)
字符串含毫秒或微秒时怎么处理
PHP 原生 DateTime 不支持毫秒级精度解析(createFromFormat() 最细到秒)。如果你拿到的是 "2024-03-15 14:22:07.123" 这类带小数秒的字符串,得手动切开处理。
- 先用
explode('.', $str)分离主时间和毫秒部分 - 用
DateTime::createFromFormat()解析前面部分(如'Y-m-d H:i:s') - 再用
modify()或setTime()补上毫秒(注意:毫秒要转成微秒传给setTime(),因为 PHP 内部用微秒) - 更简单但有损的方式:截掉小数部分,用标准方式解析,适合不要求毫秒精度的场景
示例:$parts = explode('.', '2024-03-15 14:22:07.123'); $dt = DateTime::createFromFormat('Y-m-d H:i:s', $parts[0]); $dt->modify('+' . ($parts[1] ?? 0) . 'ms');











