Symfony 以UTC格式保存日期
我目前正在尝试使用非UTC时区将日期保存在数据库中 为了获得用户时区,我有一个JS函数,它向我的后端发出AJAX请求,如下所示: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,
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());
}
}
我不太确定这是一个完美的解决方案,但它似乎有效