Symfony 以UTC格式保存日期

Symfony 以UTC格式保存日期,symfony,symfony4,Symfony,Symfony4,我目前正在尝试使用非UTC时区将日期保存在数据库中 为了获得用户时区,我有一个JS函数,它向我的后端发出AJAX请求,如下所示: import $ from 'jquery'; import jstz from 'jstz'; export default function setSessionTimezone(route) { var timezone = jstz.determine(); $.ajax({ type:'POST', async:true,

我目前正在尝试使用非UTC时区将日期保存在数据库中

为了获得用户时区,我有一个JS函数,它向我的后端发出AJAX请求,如下所示:

import $ from 'jquery';
import jstz from 'jstz';

export default function setSessionTimezone(route)
{
    var timezone = jstz.determine();
    $.ajax({
        type:'POST', async:true, cache:false, url:route, data:"timezone="+timezone.name(),
        success:function(data) { if (data.reloadPage) location.reload(); }
    });
}
仅当时区尚未处于会话中时,才会调用此方法。 所以,现在,我的后端有用户时区,这是第一步

我想把它保存在数据库里。 通过这篇文章,我发现了一些有趣的事情:

他们建议在表单中使用“model_timezone”和“view_timezone”,我也这样做了:

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UtcTypeExtension extends AbstractTypeExtension
{
    /**
     * @var SessionInterface
     */
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    /**
     * Return the class of the type being extended.
     */
    public static function getExtendedTypes(): iterable
    {
        return [TimeType::class, DateType::class];
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);

        $resolver->setDefaults([
            'model_timezone' => 'UTC',
            "view_timezone" => $this->session->get('tools_timezone')
        ]);
    }
}
好极了,它起作用了。 但只有在形式上

如果我想用Twig或PHP显示日期,我需要从会话中获取时区并更改日期时间的时区

所以我搜索了另一个选项。 我发现可以直接从理论上改变时区

这听起来很有趣,但我可能忽略了一点,因为它似乎不起作用,即使在我添加了以下配置之后:

doctrine:
    dbal:
        types:
            datetime: SomeNamespace\DoctrineExtensions\DBAL\Types\UTCDateTimeType

因此,我想知道我想做的事情是否有可能?或者如果我被迫覆盖细枝“日期”过滤器来使用我的时区?如果我想显示PHP中的日期,我还必须使用会话中的时区?

我找到了一些似乎可以回答我问题的东西

我在条令的事件“postLoad”中添加了一个侦听器

作为参考,TimezoneProvider仅从会话或UTC(如果未定义)返回DateTimezone对象

use DateTime;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping\Column;
use SomeNamespace\Provider\TimezoneProvider;
use ReflectionClass;
use ReflectionException;
use Symfony\Component\PropertyAccess\PropertyAccess;

class DateTimeConverterListener
{
    /**
     * @var AnnotationReader
     */
    private $reader;

    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;

    public function __construct(AnnotationReader $reader, TimezoneProvider $timezoneProvider)
    {
        $this->reader = $reader;
        $this->timezoneProvider = $timezoneProvider;
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
        $propertyAccessor = PropertyAccess::createPropertyAccessor();

        try {
            $reflection = new ReflectionClass(get_class($entity));

            //We search the properties where we need to update the Timezone.
            foreach ($reflection->getProperties() as $property) {
                $annotation = $this->reader->getPropertyAnnotation($property, Column::class);
                if (!$annotation instanceof Column)
                    continue;

                switch ($annotation->type) {
                    case "time":
                    case "date":
                    case "datetime":
                        /** @var DateTime|null $attribute */
                        $attribute = $propertyAccessor->getValue($entity, $property->getName());

                        if (null === $attribute)
                            continue 2;

                        //The getTimezone function returns UTC in case of no session information. And because it's a
                        // DateTime object, we don't need to set the value after the modification
                        $attribute->setTimezone($this->timezoneProvider->getTimezone());
                        break;
                }
            }
        } catch (ReflectionException $e) {
            //Abort the transformation
        }
    }
}
为了使用细枝过滤器“| date”正确显示日期,我还通过一个事件更新细枝:

use SomeNamespace\Provider\TimezoneProvider;
use Twig\Environment;
use Twig\Extension\CoreExtension;

class SetupTwigTimezoneListener
{
    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;
    /**
     * @var Environment
     */
    private $twig;

    public function __construct(TimezoneProvider $timezoneProvider, Environment $twig)
    {
        $this->timezoneProvider = $timezoneProvider;
        $this->twig = $twig;
    }

    public function onKernelRequest()
    {
        //Define the timezone of the application based of the timezone of the user
        $this->twig->getExtension(CoreExtension::class)->setTimezone($this->timezoneProvider->getTimezone()->getName());
    }
}

我不太确定这是否是一个完美的解决方案,但它似乎有效。

我找到了一些似乎能回答我问题的方法

我在条令的事件“postLoad”中添加了一个侦听器

作为参考,TimezoneProvider仅从会话或UTC(如果未定义)返回DateTimezone对象

use DateTime;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping\Column;
use SomeNamespace\Provider\TimezoneProvider;
use ReflectionClass;
use ReflectionException;
use Symfony\Component\PropertyAccess\PropertyAccess;

class DateTimeConverterListener
{
    /**
     * @var AnnotationReader
     */
    private $reader;

    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;

    public function __construct(AnnotationReader $reader, TimezoneProvider $timezoneProvider)
    {
        $this->reader = $reader;
        $this->timezoneProvider = $timezoneProvider;
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
        $propertyAccessor = PropertyAccess::createPropertyAccessor();

        try {
            $reflection = new ReflectionClass(get_class($entity));

            //We search the properties where we need to update the Timezone.
            foreach ($reflection->getProperties() as $property) {
                $annotation = $this->reader->getPropertyAnnotation($property, Column::class);
                if (!$annotation instanceof Column)
                    continue;

                switch ($annotation->type) {
                    case "time":
                    case "date":
                    case "datetime":
                        /** @var DateTime|null $attribute */
                        $attribute = $propertyAccessor->getValue($entity, $property->getName());

                        if (null === $attribute)
                            continue 2;

                        //The getTimezone function returns UTC in case of no session information. And because it's a
                        // DateTime object, we don't need to set the value after the modification
                        $attribute->setTimezone($this->timezoneProvider->getTimezone());
                        break;
                }
            }
        } catch (ReflectionException $e) {
            //Abort the transformation
        }
    }
}
为了使用细枝过滤器“| date”正确显示日期,我还通过一个事件更新细枝:

use SomeNamespace\Provider\TimezoneProvider;
use Twig\Environment;
use Twig\Extension\CoreExtension;

class SetupTwigTimezoneListener
{
    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;
    /**
     * @var Environment
     */
    private $twig;

    public function __construct(TimezoneProvider $timezoneProvider, Environment $twig)
    {
        $this->timezoneProvider = $timezoneProvider;
        $this->twig = $twig;
    }

    public function onKernelRequest()
    {
        //Define the timezone of the application based of the timezone of the user
        $this->twig->getExtension(CoreExtension::class)->setTimezone($this->timezoneProvider->getTimezone()->getName());
    }
}
我不太确定这是一个完美的解决方案,但它似乎有效