使用 JMS 序列化程序的日期时间的反序列化和序列化之间的奇怪偏移
Strange Offset between De- and Serialization of Datetime with JMS Serializer
我正在开发一个日程安排应用程序,其前端通过基于 UNIX 时间戳的时间字段与后端通信。该应用程序已在生产环境中使用了将近一年,但突然之间,谢天谢地,只有在测试服务器上,每次保存和重新加载事件时,事件的时间戳都会增加 1 小时的偏移量。我无法在本地复制它。
这是我配置序列化程序的方式。
/**
* @ORM\Column(type="datetime")
* @JMS\Type("DateTime<'U'>")
*/
private $start;
错误示例:我在美国东部时间下午 4 点安排了一个活动。我的前端计算时间戳 1614870000,将其发送到服务器。当我重新加载时,我得到 1614873600 作为时间戳,当然,在我的前端显示为下午 5 点 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);
这是saving/deserialization方面:
$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 序列化程序说我收到一个事件 $start = DateTime "2021/3/5 16:00:00 GMT+01:00" ( JMS 序列化程序默认时区似乎卡在缓存中。)
DB:“教义告诉我保存 2021/3/5 16:00:00”(<= 没有时区!)
...
正在加载该事件:
FE:“请再给我一次那个事件”
BE:“DB,你说什么?”
DB:“活动时间为 2021/3/5 16:00:00”
BE:“好的,学说,用它做一个 PHP DateTime...学说说它是 2021/3/5 16:00:00 UTC.JMS-Serializer,请告诉前端。好的,它的:1614960000"
Tadaaa。开始了。所以,我们有两个陷阱:
- Doctrines DateTime 不存储时区,在这种情况下会导致信息丢失,造成 space 误解。
- 默认时区的不同缓存导致不匹配...
所以,也许真正的问题是我选择了错误的学说数据类型?
我正在开发一个日程安排应用程序,其前端通过基于 UNIX 时间戳的时间字段与后端通信。该应用程序已在生产环境中使用了将近一年,但突然之间,谢天谢地,只有在测试服务器上,每次保存和重新加载事件时,事件的时间戳都会增加 1 小时的偏移量。我无法在本地复制它。
这是我配置序列化程序的方式。
/**
* @ORM\Column(type="datetime")
* @JMS\Type("DateTime<'U'>")
*/
private $start;
错误示例:我在美国东部时间下午 4 点安排了一个活动。我的前端计算时间戳 1614870000,将其发送到服务器。当我重新加载时,我得到 1614873600 作为时间戳,当然,在我的前端显示为下午 5 点 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);
这是saving/deserialization方面:
$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 序列化程序说我收到一个事件 $start = DateTime "2021/3/5 16:00:00 GMT+01:00" ( JMS 序列化程序默认时区似乎卡在缓存中。)
DB:“教义告诉我保存 2021/3/5 16:00:00”(<= 没有时区!)
...
正在加载该事件:
FE:“请再给我一次那个事件”
BE:“DB,你说什么?”
DB:“活动时间为 2021/3/5 16:00:00”
BE:“好的,学说,用它做一个 PHP DateTime...学说说它是 2021/3/5 16:00:00 UTC.JMS-Serializer,请告诉前端。好的,它的:1614960000"
Tadaaa。开始了。所以,我们有两个陷阱:
- Doctrines DateTime 不存储时区,在这种情况下会导致信息丢失,造成 space 误解。
- 默认时区的不同缓存导致不匹配...
所以,也许真正的问题是我选择了错误的学说数据类型?