我目前正在尝试将日期保存为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(); }
});
}
仅当时区尚未处于会话中时才调用此方法。 所以,现在,我在后端设置了用户时区,这是第一步。
我想将其保存在数据库中。 通过这篇SO帖子,我发现了一些有趣的东西:Symfony buildForm convert datetime to local and back to utc
他们建议对表单使用“ 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显示日期,则需要从会话中获取时区并更改DateTime的时区。
所以我搜索了另一个选项。 我发现this on the Doctrine Website直接从教义中更改时区。
这听起来很有趣,但是我可能遗漏了一点,因为即使我添加了以下配置,它也似乎不起作用:
doctrine:
dbal:
types:
datetime: SomeNamespace\DoctrineExtensions\DBAL\Types\UTCDateTimeType
所以我想知道我想做什么甚至可以实现?还是如果我被迫覆盖Twig的“日期”过滤器以使用我的时区?而且,如果我想显示PHP中的日期,是否还必须使用会话中的时区?
答案 0 :(得分:0)
我发现一些东西似乎可以回答我的问题。
我在原则的事件“ 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”正确显示日期,我还通过事件更新了Twig:
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());
}
}
我不太确定这是一个完美的解决方案,但它似乎可行。