问题描述
我正在开发一个调度应用程序,其前端通过基于 UNIX 时间戳的时间字段与后端通信。该应用程序已经在生产中使用了将近一年,但突然间,感谢上帝,只有在测试服务器上,每次保存和重新加载事件,都会向事件的时间戳添加 1h 偏移量。我无法在本地重现它。
这是我配置序列化程序的方式。
/**
* @ORM\Column(type="datetime")
* @JMS\Type("DateTime<'U'>")
*/
private $start;
错误示例:我在 MET 下午 4 点安排了一个活动。我的前端计算时间戳 1614870000,将其发送到服务器。当我重新加载时,我得到 1614873600 作为时间戳,当然,在我的前端显示为 5 pm MET。我可以重复这些步骤,保存并重新加载,我的活动将被安排得越来越晚......
显然,序列化和反序列化是不同步的。或读取和写入数据库。但是怎么可能呢?我已经尝试将 MySql 时区和 PHP 时区设置为荒谬的值(本地),但根本无法重现任何奇怪的行为。 (除此之外,我根本不知道系统是如何知道正确的时区的,因为显然它没有存储在数据库中,所以我认为当我切换时区时,事件至少应该改变它们的开始时间,而他们不这样做' t.) 这是一个字段在数据库中的外观:
+---------------------+
| start |
+---------------------+
| 2021-03-04 23:00:00 |
+---------------------+
这是我从数据库获取事件的方式:
$events = $repository->findAll();
$serializer = $this->container->get('jms_serializer');
$context = new SerializationContext();
$context->setSerializeNull(true);
$data = $serializer->serialize($events,'json',$context);
这是保存/反序列化方面:
$event = $serializer->deserialize($request->getContent(),Event::class,'json');
$event->setLastEditUser($user);
$event->setCreatedUser($user);
$em = $this->getDoctrine()->getManager();
$em->persist($event);
$em->flush();
您对如何调试有任何想法吗?或者为什么会发生这种情况?同样,此错误仅出现在测试服务器上,不幸的是,我无法直接访问该服务器,但尝试与管理员联系。
解决方法
好的,再做一些研究,我想我明白了:
答案是 JMS 序列化程序和学说之间关于时区的不同缓存行为。不知何故,服务器管理员更改了时区。他说他将其更改为 Europe/Berlin(来自 UTC),而我的调试输出则相反。反正。假设以下情况:
保存事件:
FE:“保存带有时间戳的事件 1614956400”
BE:“好吧,JMS Serializer 说我收到一个事件, $start = DateTime "2021/3/5 16:00:00 GMT+01:00"(JMS Serializers Default Timezone 似乎卡在缓存中。)
DB:“教义告诉我要保存 2021/3/5 16:00:00”(
...
加载该事件:
FE:“请再给我一次那个活动”
BE:“DB,你说什么?”
DB:“活动时间为 2021/3/5 16:00:00”
BE:“好的,教义,用它制作一个 PHP 日期时间......教义说它是 2021/3/5 16:00:00 UTC。JMS-Serializer,请告诉前端。好的,它的:1614960000"
Tadaaa。开始了。所以,我们有两个陷阱:
- Doctrines DateTime 不存储时区,在这种情况下会导致信息丢失,从而为误解留出空间。
- 默认时区的不同缓存导致不匹配...
那么,也许真正的问题是我选择了错误的学说数据类型?