如何处理双夏令时浏览器兼容性问题



我遇到的问题是Chrome和IE/Edge将某些JavaScript日期时间序列化为JSON给出了不同的结果 - 例如1945年夏天在英国。

我有一个JavaScript对象,其中包含通过日历组件设置的Date类型,该组件将时间设置为当地时间午夜。此对象通过 JSON.stringify 序列化,而 JSON.stringify 又使用 Date.toJSON,而 Date.toJSON 又使用 Date.toISOString。

如果我在英国区域设置中的本地日期时间为 1977 年 5 月 1 日,则序列化为"1977-04-30T23:00:00.000Z",即 UTC 1977年 4 月 30 日晚上 11 点。这很好,但是如果我从本地 1st May 1945 开始,我最终会得到不同的结果,使用 Chrome 与 IE/Edge 。Chrome 正确地给了我"1945-04-30T22:00:00.000Z"。之所以是晚上 10 点而不是晚上 11 点,是因为英国在二战期间实行双倍夏令时。

但是,IE/Edge减去一小时,这意味着JSON UTC日期时间字符串将减少一小时。

这对我来说意味着我不能信任传回服务器的JSON 序列化数据,除非我知道它来自哪个浏览器。

我正在考虑覆盖 Data.prototype.toJSON 以将序列化更改为基于本地时间的内容,但包括时区偏移量,例如"1945-05-01T00:00:00.000+0200"。至少那时我知道用户的实际意图。然而,这似乎有点极端,想知道我是否错过了什么。JSON.stringify是序列化要传送到服务器的数据的常用方法,但整个机制似乎存在缺陷。

事实上,历史时区信息因实施而异。 在不同的浏览器中,您会看到不同的结果,因为 Windows 不会跟踪英国的历史更改。 IE和经典Edge(不是Chromium版本(使用Windows时区数据进行这些转换。Chrome 提供正确的结果,因为它附带了来自 IANA 时区数据库(通过 ICU(的自己的时区数据。

对于您描述的场景,即用户从选取器中选取日期(大概是出生日期或类似内容(,处理此问题的最佳方法是这样做。 不要使用Date对象(它不是真正的日期,而是实际上是时间戳(,而是保留用户选择的原始年、月和日。 您可以为每个对象或数组保留单独的值,也可以保留自己创建的对象或数组,或者更常见的是,您可以保留 ISO 8601 格式的仅日期字符串,例如"1945-04-30"

事实上,如果你使用<input type="date"/>HTML5元素,它的value将是该格式的字符串,而不是Date对象。 还有其他日期选择器将返回该字符串,但如果您坚持使用返回Date对象的日期选择器,那么只需根据.getFullYear().getMonth().getDate()的结果构造您自己的字符串(适当地填充零(。

然后,您可以在 JSON 结果中传递该字符串,而不必担心任何一端与 UTC 之间的任何转换,也不必担心历史时区数据是否存在。

作为替代方法,如果您坚持使用Date对象,则某些使用的方法是在序列化之前将时间显式设置为中午一小时(例如中午 12 点(。 这使年月和日组件保持在同一原始日历日期上,即使时间转换为 UTC 或从 UTC 转换。

最新更新