在Javascript中使用时区和夏令时

时间:2011-02-04 22:53:52

标签: javascript datetime timezone utc dst

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

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:4)

快进到2015年,当涉及使用特定区域设置来格式化其他时区的日期时,有两种选择。

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

为了获得最大的可移植性,请使用moment.js库。片刻带有捆绑的80+ locales

  1. 使用时间戳和UTC偏移:

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

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

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

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

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

    使用整数数组:

        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时间),并且应该仅用于日期格式化和显示 - 不应该传递

答案 2 :(得分:0)

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