laravel模型tojson()中日期默认为iso 8601格式,因carbon::__tostring()不走$model->dateformat;需重写serializedate()方法或用jsonresource定制格式。

为什么 $model->toJson() 里的日期不是你想要的格式
因为 Laravel 默认用 Carbon 实例序列化日期,而 Carbon 的 __toString() 返回 ISO 8601 格式(如 "2024-05-20T09:30:45.000000Z"),不走模型里定义的 dateFormat。这个格式对前端友好,但如果你需要 "Y-m-d H:i:s" 或带时区偏移的本地时间,直接调用 toJson() 就会踩坑。
- 仅设置
protected $dateFormat = 'Y-m-d H:i:s';对 JSON 序列化无效 -
toArray()也不受$dateFormat影响,它只控制数据库写入/读取时的解析 - 全局修改
Carbon::serializeUsing()会影响所有地方,容易误伤
在模型里用 $casts + date 或 datetime 配合 serializeDate()
这是最干净、作用域明确的做法:让每个模型自己决定 JSON 里日期长什么样。
- 在模型中重写
serializeDate()方法,返回你想要的格式字符串,比如:protected function serializeDate(\DateTimeInterface $date) { return $date->format('Y-m-d H:i:s'); } - 确保该字段已声明为
date或datetime类型的$casts,否则不会进这个方法:protected $casts = [ 'created_at' => 'datetime', 'updated_at' => 'datetime', 'published_at' => 'datetime', ]; - 注意:这个方法只影响
toJson()、toArray()和 API 资源(JsonResource)中的日期,不影响数据库操作
API 资源里手动格式化(适合需要多版本输出的场景)
当同一个模型要输出不同格式(比如管理后台要完整时间戳,APP 接口只要日期),别硬改模型,用 JsonResource 更灵活。
- 在资源类的
toArray()里用$model->created_at->format('Y/m/d')直接处理 - 避免重复调用
format()导致性能浪费,可先赋值:'created_date' => $this->created_at->format('Y-m-d'), 'created_time' => $this->created_at->format('H:i'), - 如果字段可能为
null,记得判空,否则抛Call to a member function format() on null
全局统一处理但留出例外(慎用)
项目早期就确定所有 API 日期都用 "Y-m-d H:i:s",且不区分时区,可以考虑全局钩子,但得预留绕过机制。
- 在
AppServiceProvider::boot()中设置:Carbon::serializeUsing(function ($carbon) { return $carbon->format('Y-m-d H:i:s'); }); - 副作用明显:所有第三方包、日志、队列任务里用到
Carbon序列化的都会被改掉 - 若某个模型必须保持 ISO 格式,得在它的
serializeDate()里显式调用parent::serializeDate($date)
真正麻烦的不是怎么改格式,而是改完之后忘了检查 Swagger 文档、前端 mock 数据、测试用例里的时间断言——它们全依赖旧格式。动手前先 grep 一遍 "T\d{2}:\d{2}:\d{2}" 和 "\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}" 出现的地方。










