mysql datetime 字符串不能直接传给php date(),须先转datetime对象再format;推荐new datetime($str)并显式指定时区,避免时区偏差导致显示错误。

MySQL DATETIME 字段直接用 date() 格式化会出错
PHP 的 date() 函数只接受 Unix 时间戳(int),而 MySQL 返回的 DATETIME 或 TIMESTAMP 字段是字符串,形如 "2026-10-13 23:51:00"。直接传给 date() 会导致返回空或错误结果。
常见错误现象:
-
date('Y-m-d', '2026-10-13 23:51:00')返回1970-01-01 - 不报错但结果完全不对,尤其在时区未设或跨日时更隐蔽
正确做法是先转成时间戳,再格式化:
- 用
strtotime():简单但有局限(比如无法解析含毫秒、时区缩写或非标准分隔符的字符串) - 用
DateTime::createFromFormat():精准可控,推荐用于数据库字段(格式已知且固定) - 用
new DateTime($mysql_datetime_string):最常用,自动识别 ISO 8601 格式,对Y-m-d H:i:s兼容性好
从 MySQL 读取时间后,用 DateTime 对象做格式化最稳妥
假设你用 PDO 查询得到一行数据:$row['created_at'] === '2026-10-13 23:51:00',直接构造 DateTime 是首选路径。
示例代码:
$dt = new DateTime($row['created_at']);
echo $dt->format('d M Y'); // 输出:13 Oct 2026
注意点:
- 如果数据库字段是
TIMESTAMP且 MySQL 时区设为 UTC,而 PHP 默认时区是Asia/Shanghai,new DateTime()会按本地时区解释该字符串——这可能导致 +8 小时偏移。解决方法是显式指定时区:new DateTime($row['created_at'], new DateTimeZone('UTC')) - 若字段含毫秒(如
'2026-10-13 23:51:00.123'),new DateTime()能处理,但strtotime()会截断毫秒部分 -
DateTimeImmutable更安全,避免意外修改原对象,尤其在函数间传递时
date_format() 不是独立函数,它是 DateTime::format() 的别名
查文档时容易误以为 date_format() 是类似 date() 的全局函数,其实它只是面向对象方法的函数式别名,必须传入 DateTime 实例。
错误写法:
date_format('Y-m-d', $timestamp); // ❌ 参数顺序错,且第一个参数不是 DateTime 对象
正确写法只有两种:
-
$dt->format('Y-m-d')(推荐,语义清晰) -
date_format($dt, 'Y-m-d')(合法但不直观,易和date()混淆)
性能上无差异,但可读性和维护性上,直接调用对象方法更明确——你知道自己在格式化哪个时间点,而不是靠参数顺序猜。
时区不一致是格式化结果偏差的最常见原因
MySQL 和 PHP 各自维护一套时区设置,两者不联动。即使 MySQL 的 TIMESTAMP 存的是 UTC,PHP 仍可能按本地时区解析字符串,导致显示时间比实际早/晚若干小时。
排查步骤:
- 确认 MySQL 服务器时区:
SELECT @@time_zone; - 确认 PHP 当前时区:
date_default_timezone_get() - 检查 PDO 获取的值是否已受 MySQL 连接时区影响(例如
SET time_zone = '+00:00')
最可靠的做法是:在数据库层统一用 UTC 存储,在应用层用 DateTime 显式指定源时区,再转换为目标时区显示:
$utc = new DateTime($row['updated_at'], new DateTimeZone('UTC'));
$utc->setTimezone(new DateTimeZone('Asia/Shanghai'));
echo $utc->format('Y-m-d H:i');
这个链路清晰、可控,不会因环境配置变化而意外偏移。忽略时区处理,是线上时间显示错误最常被忽略的环节。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











