使用Carbon转换数据库date类型字段时区未达预期如何解决
问题原因
Laravel 模型中如果在 $dates 属性、$casts 属性中声明了 date_ini 为日期类型,查询时框架会自动将该字段原始字符串转换为 Carbon 实例,且默认使用项目配置文件中的 app.timezone(通常默认值为 UTC)初始化时区。此时你调用 Carbon::parse() 传入已经生成的 Carbon 对象时,第二个指定时区的参数不会生效,相当于直接对一个已经标记为 UTC 时区的 2018-08-25 00:00:00 实例做 UTC 转换,结果自然不会变化。
无需修改数据库字段的解决方案
以下方案都可以直接实现需求,不需要修改字段存储类型:
方案1:读取字段原始字符串再解析
直接获取数据库存储的原始字符串值,再用指定时区解析:
// 方法1:强转为字符串 $from = Carbon::parse((string) $operation->date_ini, 'Europe/Paris')->timezone('UTC'); // 方法2:用getRawOriginal取数据库原始值,避免模型转换逻辑影响 $from = Carbon::parse($operation->getRawOriginal('date_ini'), 'Europe/Paris')->timezone('UTC');
方案2:直接修改现有Carbon实例的时区标记
不需要重新解析字符串,直接修改已有的Carbon实例的时区标记(不改变当前的年月日时分秒数值),再转UTC即可:
$from = $operation->date_ini->shiftTimezone('Europe/Paris')->timezone('UTC');
方案3:在模型中自定义访问器,一劳永逸
如果该字段存储的始终是法国时区的日期,可以直接在Operation模型中为该字段定义访问器,后续所有读取场景都会自动按法国时区初始化:
// 放在Operation模型中 use Carbon\Carbon; use Illuminate\Database\Eloquent\Casts\Attribute; protected function dateIni(): Attribute { return Attribute::make( get: fn ($value) => Carbon::parse($value, 'Europe/Paris'), ); }
之后使用时直接转换即可:
$from = $operation->date_ini->timezone('UTC');
内容的提问来源于stack exchange,提问作者Juliatzin
相关产品推荐
相关产品推荐

