PHP原生不支持毫秒时间戳直接转日期,因date()和DateTime仅接受秒级时间戳;13位毫秒值未除1000会导致年份错乱(如1717023600000被误为1717年),且需显式设时区并用round()四舍五入到秒。

PHP 原生不支持毫秒级时间戳直接转日期——date() 和 DateTime 构造函数默认只接受秒级整数,传入 13 位毫秒时间戳会解析为错误年份(比如 1717023600000 被当 1717 年处理)。
为什么直接用 date('Y-m-d', 1717023600000) 会出错
PHP 的时间函数底层依赖 Unix 秒级时间戳(1970-01-01 起的秒数),而毫秒时间戳是它的 1000 倍。直接传入会导致数值溢出、年份错乱(如显示 56380 年或负数年份),DateTime::__construct() 同样拒绝 13 位数字。
- 常见错误现象:
DateTime::__construct(): Failed to parse time string '1717023600000' - 根本原因:毫秒值未折算,且未指定时区上下文
- 注意:
strtotime()也无法识别毫秒字符串,它只解析日期格式文本
一行代码安全转换毫秒时间戳(含时区控制)
最简且健壮的做法是先除以 1000 取整,再交由 DateTime 处理,并显式设置时区——这能避免服务器默认时区干扰:
echo (new DateTime())->setTimestamp((int) round(1717023600000 / 1000))->setTimezone(new DateTimeZone('Asia/Shanghai'))->format('Y-m-d H:i:s');
说明:
立即学习“PHP免费学习笔记(深入)”;
-
round(... / 1000)确保四舍五入到最近秒,比(int)截断更合理(如1717023600123→1717023600) -
setTimezone()必须显式调用,否则用系统默认时区(date_default_timezone_get()可能不是你想要的) - 如果只要日期部分,把
format('Y-m-d H:i:s')换成format('Y-m-d')即可
封装成可复用函数(推荐用于项目)
实际开发中重复写 new DateTime() 链式调用易出错,建议封装:
function ms2date(int $ms, string $format = 'Y-m-d H:i:s', string $tz = 'Asia/Shanghai'): string{
return (new DateTime())
->setTimestamp((int) round($ms / 1000))
->setTimezone(new DateTimeZone($tz))
->format($format);
}
使用示例:
-
ms2date(1717023600000)→"2024-05-30 15:00:00" -
ms2date(1717023600123, 'c')→ ISO 8601 格式,含时区偏移 - 时区名必须合法,非法如
'GMT+8'会抛异常,应改用'Asia/Shanghai'或'Etc/GMT-8'
真正容易被忽略的是时区和舍入方式——毫秒末三位不是总能丢弃,尤其做日志对时、定时任务校验时,round() 比强制 (int) 更贴近真实时间点。



















