我的应用时区设置为“美国/蒙特利尔”。
我有两个日期时间字段“开始”和“结束”,每个字段都使用 laravel $casts 属性转换为日期时间:
protected $casts = [
'start' => 'datetime',
'end' => 'datetime'
];
当我使用以下数据创建我的模型实例时:
MyModel::create(
[
'start' => "2022-02-08T20:45:58.000Z", // UTC time
'end' => "2022-02-08T20:45:58.000Z",
]
);
创建的模型保持相同的时间 (20:45),但时区设置为美国/蒙特利尔:
App\MyModel {#4799
id: 44,
created_at: "2022-02-08 15:49:02",
updated_at: "2022-02-08 15:49:02",
start: 2022-02-08 20:45:58,
end: 2022-02-08 20:45:58,
}
当我访问开始和结束属性时,我得到的时间是相同的,但美国/蒙特利尔时区是这样的:
// accessing 'start' attribute of the instance I just created
Illuminate\Support\Carbon @1644371158 {#4708
date: 2022-02-08 20:45:58.0 America/Montreal (-05:00),
我发现让它正常工作的唯一方法是在保存之前手动设置时区:
MyModel::create(
[
'start' => Carbon::parse("2022-02-08T20:45:58.000Z")->setTimeZone(config('app.timezone')),,
'end' => Carbon::parse("2022-02-08T20:45:58.000Z")->setTimeZone(config('app.timezone')),,
]
);
我认为这是重复的,设置应用程序时区还不够吗?有没有更好的方法来做到这一点?我知道我应该将我的应用程序时区设置为 UTC(这是我通常所做的)但是这个项目已经有很多这个时区的数据,我不确定如何转换它。
谢谢。
最佳答案
鉴于 laravel 只会将日期存储在执行 $date->format('Y-m-d H:i:s')
的模型中,该模型将其格式化为当前时区,但不保留时区信息,然后检索它,就好像它在应用程序时区(大部分时间是 utc)中一样,这会产生差异,因为如果您设置的值有与应用不同的时区
基本上就是这样
Carbon\Carbon::parse(Carbon\Carbon::parse('2022-11-08 00:00', 'America/Montreal')->format('Y-m-d H:i:s'), 'UTC');
Carbon\Carbon @1667865600 {#4115
date: 2022-11-08 00:00:00.0 UTC (+00:00), // As you can see it is UTC,
// which is ok because the database does not store the timezone information,
// but the time is 2022-11-08 00:00 and should be 2022-11-08 05:00:00 in UTC
}
// This would yield the correct result
Carbon\Carbon::parse(Carbon\Carbon::parse('2022-11-08 00:00', 'America/Montreal')->setTimezone('UTC')->format('Y-m-d H:i:s'), 'UTC');
您可以创建自己的模型扩展来覆盖 setAttribute
方法并从此类扩展而不是将所有日期自动转换为您的应用时区
<?php
namespace App;
use DateTimeInterface;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Model as BaseModel;
class Model extends BaseModel
{
/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
public function setAttribute($key, $value)
{
if ($value instanceof CarbonInterface) {
// Convert all carbon dates to app timezone
$value = $value->clone()->setTimezone(config('app.timezone'));
} else if ($value instanceof DateTimeInterface) {
// Convert all other dates to timestamps
$value = $value->unix();
}
// They will be reconverted to a Carbon instance but with the correct timezone
return parent::setAttribute($key, $value);
}
}
关于laravel - 当时区与 UTC 不同时如何存储日期时间(Laravel),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71040870/