如何在CakePHP中使用时区持久化DatetTime

如何在CakePHP中使用时区持久化DatetTime,cakephp,cakephp-4.x,Cakephp,Cakephp 4.x,我有一个使用UTC时区的MySQL,并尝试将一个CakePHP实体保存到数据库中的datettime列中 当PHP DatetTime对象具有时区(与UTC不同)时,CakePHP在保存期间不会将该值转换为UTC 我写了一个简短的测试来证明这个问题 公共函数testTryCreateReservation():void { $e=$this->Reservations->newEmptyEntity(); $now=new\DateTime(); $start=new\DateTime('now

我有一个使用UTC时区的MySQL,并尝试将一个CakePHP实体保存到数据库中的datettime列中

当PHP DatetTime对象具有时区(与UTC不同)时,CakePHP在保存期间不会将该值转换为UTC

我写了一个简短的测试来证明这个问题

公共函数testTryCreateReservation():void
{
$e=$this->Reservations->newEmptyEntity();
$now=new\DateTime();
$start=new\DateTime('now',new\DateTimeZone('Europe/Vienna');
$start->setTimestamp($now->getTimestamp());
$end=new\DateTime('now');
$end->setTimestamp($now->getTimestamp());
$e->start\u time=$start;
$a=$this->Reservations->get($a->id);
$this->assertEquals($end,$a->end\u time);
$this->assertEquals($start,$a->start_time);//此操作失败
}
这是phpunit输出

Failed asserting that two DateTime objects are equal.
--- Expected
+++ Actual
@@ @@
-2020-09-02T07:54:45.000000+0200
+2020-09-02T07:54:45.000000+0000
CakePHP不应该转换该值吗?

启用时区转换 当列为
datetime
类型时,ORM将转换时区,并且您在相应的数据库类型实例上配置数据库时区(
\Cake\database\type\DateTimeType

您可以在
bootstrap.php
中执行此操作,底部有一节介绍如何构建和配置数据库类型:

\Cake\Database\TypeFactory::build('datetime')->setDatabaseTimezone('UTC');
还应注意的是,这也将以另一种方式启用转换,即从数据库时区转换为应用程序的默认时区(
App.defaultTimezone
)!如果不需要,可以通过
setKeepDatabaseTimezone()
方法禁用它:

\Cake\Database\TypeFactory::build('datetime')->setKeepDatabaseTimezone(true);
然后将使用(未转换为)为数据库类型配置的时区创建对象

我想如果在食谱中有一个关于数据库时区转换的专门章节,也不会有什么坏处

仅对特定列应用时区转换 请注意,如果您不希望全局应用,还可以映射新类型并仅将其分配给特定的表列:

//在bootstrap.php中
\Cake\Database\TypeFactory::map('customDateTime',\Cake\Database\Type\DateTimeType::class);
\Cake\Database\TypeFactory::build('customDateTime')->setDatabaseTimezone('UTC');
//在希望将此类型应用于特定列的表类中
受保护函数\u initializeSchema(\Cake\Database\Schema\TableSchemaInterface$Schema):\Cake\Database\Schema\TableSchemaInterface
{
$schema->setColumnType('column_name','customDateTime');
返回$schema;
}
另见

非常感谢
setDatabaseTimezone('UTC')
似乎有效。那么Datasource.default.timezone是做什么的呢?这听起来像是为蛋糕内部时间转换(创建和修改日期)和用户空间日期时间字段设置了单独的设置。是这样吗?@GerdK这是数据库连接的时区配置,它与CakePHP的日期/时间功能完全分离。它影响支持时区的DBMS功能,例如
NOW()
在给定时区中生成日期,或者在MySQL上,将
时间戳
列类型从会话时区转换为UTC进行存储,反之亦然进行检索。CakePHP转换层的要点是跨数据库兼容性、时区转换的集中化,因此故障点较少。@GerdK根据我的经验,您通常最好遵循“一个时区来管理所有时区”的方法,即在UTC中存储所有内容,并在需要时在应用程序中进行转换。