关于datetime:在Javascript中使用时区和夏令时

Working with timezones and daylight savings time in Javascript

我的单页javascript应用程序通过REST调用以JSON格式检索数据。使用标准ISO8601格式的UTC时区格式化日期,例如2011-02-04T19:31:09Z

注册该服务时,用户从下拉列表中选择他们的时区。此时区可能与用户浏览器的时区不同。 javascript应用程序始终知道用户选择的时区是什么。

我知道如何将UTC字符串转换为日期。我知道Javascript只代表当地时区的日期。

但是我遇到了麻烦,想知道如何显示为时区而不是用户的本地时区格式化的日期。它必须在所有日期考虑DST。在内部,我希望将所有日期作为UTC处理,并且仅在显示时转换为另一时区中日期的字符串表示。我需要在用户个人资料中选择的时区中显示日期,而不是浏览器的时区。

我已经尝试过服务器发送用户浏览器时区和用户配置文件时区之间的时区偏移差异(以毫秒为单位)。但我发现我不能只发送一个偏移值,但需要为每个日期发送一个偏移量来解释夏令时的变化。

有关如何显示各种时区格式的日期的任何建议或示例代码?到目前为止我找到的选项:

  • 服务器将日期作为已在正确时区格式化的字符串发送,并且不在客户端上进行日期解析或操作。这使得在客户端做某些事情很困难,如果不是不可能的话。
  • 使用诸如https://github.com/mde/timezone-js之类的库,其中包括整个Olson TZ数据库到Javascript中。这意味着加载时间越长,内存使用量越多等。
  • 使用发送到客户端的每个日期发送timezoneOffsetMillis值。这会导致混乱的JSON数据和非最佳REST接口。
  • 有没有更简单或更好的解决方案?


    2是个坏主意,因为正如你所指出的那样,它增加了加载时间。如果我是你,我会做1和3的组合。我不同意这会使JSON数据混乱或REST接口不是最佳的。

    这是一种经典的权衡,可以在协议中接受更多的复杂性,以简化客户端代码。


    快进到2015年,在使用特定区域设置格式化其他时区的日期时,有两个选项。

    在该示例中,我使用法语区域设置,并将使用(UTC + 5)日期2016年3月27日,2h15,这在西欧没有观察到(由于DST更改,时钟从2h00移动到3h00)这是一个常见的来源错误。

    为了获得最大的可移植性,请使用moment.js库。 Moment带有捆绑的80多种语言环境。

  • 使用时间戳和UTC偏移量:

    1
    2
    moment(1459026900000).utcOffset(300).locale('fr').format("LLLL")
    //"dimanche 27 mars 2016 02:15"
  • 使用整数数组(请注意,在一瞬间,月份是基于0的,就像在本机JS Date对象中一样)

    1
    2
    moment.utc([2016,3-1,27,2,15]).locale('fr').format("LLLL")
    //"dimanche 27 mars 2016 02:15"
  • 您可以通过在http://momentjs.com/上的浏览器开发工具中运行代码来测试这些方法。

    这里棘手的部分是使用moment.utc创建一个带有UTC标志的时刻日期对象,这意味着当该日期被格式化时,它不会被转换为用户的时区,而只是按原样显示(并且因为UTC没有观察到DST,它不容易出现DST错误)。

    未来的原生解决方案:使用Intl对象

    (注意截至2015年底,Chrome,Firefox,IE11支持此解决方案,但Safari 9仍然不支持)

    使用整数数组:

    1
    2
    3
    4
    5
        new Intl.DateTimeFormat('fr-FR', { timeZone: 'UTC', weekday: 'long',
              month: 'long', year: 'numeric', day: 'numeric', hour: 'numeric',
              minute: 'numeric' })
          .format(Date.UTC(2016,3-1,27,2,15))
        //"dimanche 27 mars 2016 02:15"

    这里的关键是再次使用Date.UTCtimeZone: 'UTC'来确保提供的日期不会转换为用户的本地时区。

    请注意,在这两种情况下,我们都使用UTC方法,只是为了确保日期将按原样使用而不进行转换。重要的是要认识到这些日期是伪造的UTC日期(它们代表给定任意时区的时间,而不是UTC时间),并且应该仅用于日期格式化和显示 - 不应该传递。


    有同样的问题。我猜是#1是解决方案。您应该将特定容器中的日期(年,月,日,小时)的所有组件从客户端发送到服务器