Symfony Doctrine - 设置时区

4

我有多个运行在同一服务器上的Symfony应用程序,每个应用程序可能需要不同的时区。

对于php来说,可以通过使用不同的fpm池并在池配置中设置时区来实现:

php_admin_value[date.timezone] = America/New_York

但对于MySQL,我需要发出以下语句:
"SET time_zone = 'America/New_York';

作为连接后的第一个查询,或添加到PDO构造函数中的$options数组:

PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone = 'America/New_York';"

如何实现这个目标?


5
不要这样做。在所有地方都使用UTC操作,在应用程序中使用适当的时区格式来表示日期,这种方法更加简单清晰。在Twig束配置中,甚至可以设置时区,这样Twig会自动进行转换。 - Mike Doe
我自己没有尝试过,但Doctrine dbal选项配置应该允许您设置时区。但我同意使用UTC是更好的方法。 - Cerad
另一种方法是使用高优先级内核请求监听器,在其他任何操作之前执行您的set time_zone语句。 - Cerad
@emix 我的数据按日期聚合,我不存储时间,但如果现在发生了什么,我会将其存储在日期为2019-01-13的列中。因此,日期可能会根据所处的时区而变化。 - the_nuts
1
我想最好的方法是在应用程序级别计算日期并将MySQL保留为UTC,或者只有在没有其他方法时才设置它。 - the_nuts
3个回答

5
您可以使用PostConnect Doctrine事件... https://www.doctrine-project.org/projects/doctrine-dbal/en/2.9/reference/events.html#postconnect-event 这对于在执行任何SQL语句之前配置连接非常有用。
例如:
<?php

namespace App\EventListener;

use Doctrine\DBAL\Event\ConnectionEventArgs;

/**
 * My initializer
 */
class  MyPdoInitializerListener
{
    public function postConnect(ConnectionEventArgs $args)
    {
        $args->getConnection()
            ->exec("SET time_zone = 'America/New_York'");
    }
}

不要忘记将监听器添加到 services.yaml。
# services.yaml

    # ...

    App\EventListener\MyPdoInitializerListener:
        tags:
            - { name: doctrine.event_listener, event: postConnect }

1
请注意,此解决方案已在DBAL v3.5中弃用。 - Andrei Sosnin
https://github.com/doctrine/dbal/blob/3.5.x/UPGRADE.md#deprecated-extension-via-connection-events - Andrei Sosnin

2
为了扩展SilvioQ的回答,我编写了以下代码片段,以从PHP环境继承时区,假设date_default_timezone_set()之前已经被调用以设置正确的时区:
当这些命名的时区(如"America/New_York")在MySQL/MariaDB中不可用且您无法控制服务器时,此解决方案比命名时区更具优势。
public function postConnect(ConnectionEventArgs $args) {
    $tz = new DateTimeZone(date_default_timezone_get());
    $offset = $tz->getOffset(new DateTime('now'));
    $abs = abs($offset);
    $str = sprintf('%s%02d:%02d', $offset < 0 ? '-' : '+', intdiv($abs, 3600), intdiv($abs % 3600, 60));
    $args->getConnection()->exec("SET time_zone = '$str'");
}

感谢这个回答。我有一个类似的问题,symfony/doctrine/php 的时区与mysql不同,我不知道在数据库上设置时区会产生哪些副作用,所以我计算了php Datetime和mysql中now-function的偏移量,并将其设置为偏移量。 - sneaky

0
从Doctrine DBAL的3.5版本开始,SilvioQ提出的解决方案已被弃用。
Doctrine文档建议使用中间件类来实现数据库驱动程序。在DBAL代码中可以找到这种实现的示例:src/Logging/Middleware.php

2
链接已失效。 - undefined
2
链接已失效。 - Kid Diamond
1
将版本3.5更改为3.6是可行的;https://github.com/doctrine/dbal/blob/3.6.x/src/Logging/Middleware.php - Adambean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接