【问题标题】:How to deal with double daylight savings time browser compatibility issues如何处理双夏令时浏览器兼容性问题
【发布时间】:2019-11-28 15:07:26
【问题描述】:

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

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

如果我的英国语言环境中有一个本地日期时间,比如 1977 年 5 月 1 日,则序列化为 "1977-04-30T23:00:00.000Z",即 UTC 时间 1977 年 4 月 30 日晚上 11 点。这个很好,但是如果我从本地 1945 年 5 月 1 日开始,我最终会使用 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 是序列化数据以发送到服务器的常用方法,但整个机制似乎存在缺陷。

【问题讨论】:

    标签: javascript json datetime timezone utc


    【解决方案1】:

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

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

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

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

    作为替代方案,如果您在使用Date 对象时遇到问题,那么一些使用的方法是在序列化之前将时间显式设置为中午时间(例如中午 12 点)。即使时间转换为/从UTC转换,这也会使年月和日组件保持在相同的原始日历日期。

    【讨论】:

    • 谢谢,我确实想知道人为地将时间设置为中午,但这看起来太丑陋了,我想我一定遗漏了一些明显的东西。显然不是。我将仔细看看我可以用我的日历组件做什么。
    • 我看到你也参与了Moment.js。我已经在使用它了,所以只是想知道在这种情况下是否有什么我可以有用的东西?
    • 您可以执行moment(dateObjectFromYourPicker).format('YYYY-MM-DD') 之类的操作来发送日期。您也可以在没有 Moment 的情况下执行 dateObjectFromYourPicker.toLocaleDateString('en-CA', { dateStyle: 'short' })。 (en-CA 给出了 yyyy-mm-dd 格式,因此您可以将其视为 ISO 8601)
    • 您也可以考虑使用this approach 来使用您的 JSON。
    • 我想我可能会沿着覆盖 Date.prototype.toJSON 的路线走下去,我不妨使用 Moment,因为它已经是一个依赖项。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2010-11-17
    • 2012-06-07
    • 2014-09-12
    • 1970-01-01
    • 2018-01-09
    • 2021-08-04
    • 1970-01-01
    相关资源
    最近更新 更多