Laravel升级至8.0后timestamp时间戳存储日期格式错误问题
问题根因
这个问题和PHP时区配置没有关系,核心是两个逻辑错误:
- 你之前写的按操作系统分支返回日期格式的
getDateFormat()逻辑本身不成立:SQL Server的日期解析规则和PHP运行在Windows还是Linux没有绑定关系,旧版Laravel 5.7下这套逻辑能跑,是因为当时框架对SQL Server驱动的日期格式化没有做毫秒精度适配,升级到Laravel 8之后,框架调整了Eloquent时间戳双向序列化的优先级,会完全使用getDateFormat()返回的格式做写入数据库转字符串和读取数据转时间对象两个操作,Windows分支返回的Y-d-m H:i:s.v本身就是日、月顺序颠倒的格式,写入时自然会把月和日存反。 - 你尝试把全环境格式统一成
Y-d-m H:i:s.v的做法,相当于让框架读取数据时也按日月颠倒的格式解析时间,后续用strtotime()、date()处理字符串时自然会出现展示错位。
解决方案
不要通过判断操作系统返回不同日期格式,按以下步骤配置即可同时兼容存储、读取、全场景展示:
1. 统一模型日期格式
删除所有SQL Server相关模型里原有按系统判断的getDateFormat()逻辑,替换为固定的标准格式:
public function getDateFormat() { // 标准年-月-日顺序,兼容SQL Server datetime/datetime2类型的3位毫秒精度 return 'Y-m-d H:i:s.v'; }
注意:格式必须保持
Y-m-d的年-月-日顺序,不能写为Y-d-m,否则框架读取数据库值反序列化时间对象时就会出现日月错位。如果你的SQL Server版本低于2008、不支持毫秒精度,直接把格式改为Y-m-d H:i:s即可。
2. 配置PDO连接强制日期格式
打开config/database.php,找到对应SQL Server的连接配置项(驱动为sqlsrv),在options参数中添加强制日期格式配置,避免PDO驱动自动转换日期导致的顺序错位:
'connections' => [ 'sqlsrv' => [ // 保留原有driver、host、database、username、password等配置不动 'options' => [ PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8, // 强制连接全程使用ISO标准年-月-日顺序解析日期 PDO::SQLSRV_ATTR_DATETIME_FORMAT => "Y-m-d H:i:s.v", ], ], ],
配置完成后执行php artisan config:clear清除配置缓存。
3. 优化模板层时间格式化逻辑
不要用原生date()+strtotime()的组合处理Eloquent时间字段:Laravel默认会把created_at、updated_at字段转为Carbon时间实例,直接调用Carbon自带的format()方法做格式化即可,完全不会出现解析错位:
// 替换原有模板里的date+strtotime写法 <p>updated at: {{ $model->updated_at->format('d/m/Y H:i:s') }}</p>
Carbon内部是按时间戳数值存储时间的,只要模型读取时解析正确,不管怎么格式化都不会出现日月反转的问题。
验证方法
改完后做两步校验即可确认修复生效:
- 新建一条测试模型数据,直接在SQL Server中查询对应字段值,确认存储的日期日月顺序正确
- 取出该条测试数据,输出格式化后的时间字段,确认展示顺序符合预期
内容的提问来源于stack exchange,提问作者Alec
相关产品推荐
相关产品推荐

