【问题标题】:Stop javascript Date function from changing timezone offset停止 javascript Date 函数更改时区偏移量
【发布时间】:2013-07-19 01:41:08
【问题描述】:

所以我有需要从字符串转换为日期对象的 iso 日期时间。如何保持日期不将其转换为本地浏览器时区。

new Date('2013-07-18T17:00:00-05:00')
Thu Jul 18 2013 18:00:00 GMT-0400 (EDT)

我想得到

2013 年 7 月 18 日星期四 17:00:00 GMT-0500 (XX)

【问题讨论】:

  • ISO 格式日期的点将被转换回您的时区...
  • 你不能。 JavaScript Date 对象不存储任何时区信息,当输出/toStringing/记录它们时,它们将使用您的本地浏览器时区(不幸的是默认)或 UTC(使用显式方法)。
  • 但是,如果我要显示的内容不在浏览器时区中怎么办。为什么不能日期解析字符串并将日期对象设置为iso字符串中指定的时区偏移量。
  • 如果你使用 UTC/GMT,有 toUTCString() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 我刚刚遇到这个问题,FireFox 不会弄乱我的日期,但所有其他浏览器都会这样做。

标签: javascript date datetime timezone


【解决方案1】:

虽然 MomentJS 是一个很棒的库,但它可能无法为每个用例提供解决方案。例如,我的服务器以 UTC 格式提供日期,并且当日期的时间部分未保存在数据库中(因为它无关紧要)时,客户端会收到一个默认时间全为零的字符串 - 午夜 - 并以+0000 的偏移量。然后浏览器会根据我的本地时区自动调整,并将时间向后拉几个小时,结果是前一天。

MomentJs 也是如此。

一种解决方案是切掉字符串的时间部分,然后按照其他答案中的说明使用 MomentJS。

但是如果 MomentJS 不是一个可行的选项会发生什么,即我已经有很多地方使用 JS Date 并且不想更新这么多代码行?问题是如何首先阻止浏览器根据本地时区转换日期。答案是,当日期是 ISO 格式时,你不能。

然而,没有规定您传递给 JavaScript 的 Date 构造函数的字符串必须是 ISO 格式。如果您只是用/ 替换分隔年、月和日的-,您的浏览器将执行任何转换。

在我的例子中,我只是更改了 Dates 服务器端的格式,问题就解决了,而无需使用 MomentJS 更新所有客户端 JS 日期。

请注意,JavaScript 的 Date 类的 MDN 文档在解析字符串以创建 Date 实例时警告不可预测的浏览器行为。

【讨论】:

  • 我有一个类似的问题,不应该转换的本地时间,以提交到不同时区的服务器。我的解决方案是在准备运输时将“.local”附加到时间字符串。查看所有调试和日志很明显,这是一个无法解析的时间,旨在表示某个特定商店的本地时间。
【解决方案2】:

您无法更改 Javascript 的这种行为,因为它是 Javascript 工作的唯一简单方式。发生的事情只是 Javascript 查看时间偏移,计算匹配的时间戳,然后向操作系统询问该时间戳在本地时区中的表示。这里要理解的关键是 -05:00 不是时区的指示,而只是与 UTC 的偏移。

时区是复杂的野兽,只是武断的政治决定。操作系统提供了在本地时区显示时间的服务,而不是在其他时区显示时间。为此,您必须考虑到 DST 之类的东西,这简直就是地狱。

与时间管理一样,解决此问题的唯一体面方法是使用专用库。在 Javascript 中,您会发现 Moment.jsMoment.Timezone.js 非常有用。

例如http://codepen.io/Xowap/pen/XKpKZb?editors=0010

document.write(moment('2013-07-18T17:00:00-05:00').tz('America/New_York').format('LLL'));

作为奖励,您可以从 Moment.js 获得大量格式化/解析功能。

还请注意,只要您使用 ISO 8601,您的日期就可以被精确定位到一个精确的时刻,从而显示在您喜欢的任何时区。换句话说,JS“转换”你的日期并不重要。

【讨论】:

    【解决方案3】:

    您可以使用 Moment.js 等库来执行此操作。

    参见字符串+格式解析

    http://momentjs.com/docs/#/parsing/string-format/

    以下内容应解析您提供的日期,但您可能需要根据需要对其进行修改。

    var dateString = "2013-07-18T17:00:00-05:00";
    
    var dateObject = moment(dateString, "YYYY-MM-DDTHH:mm:ssZ").toDate();
    

    或者,请参阅 Moment 的字符串解析器,它看起来就像您提供的格式,除了时间的秒数和时区之间的空格。

    http://momentjs.com/docs/#/parsing/string/

    【讨论】:

      【解决方案4】:

      这是一个老问题,最近与一个新问题的答案相关联,但现有答案似乎都没有完全解决原始问题。

      在许多情况下,在接收到的时区中格式化和显示日期时间字符串的最简单方法是根本不将该字符串转换为Date 对象。相反,只需解析日期时间字符串并将这些部分重新组合成所需的格式。例如,如果您可以在问题中请求的输出中没有星期几,您可以执行以下操作来处理请求的输入和输出格式(包括星期几会增加足够的复杂性,可能那时值得使用图书馆)。当然,这种方法需要根据您在客户端收到的日期时间字符串的格式进行修改。

      const months = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'};
      const format = (datetime) => {
        const [date, time] = datetime.split('T');
        const [y, m, d] = date.match(/\d+/g);
        const [t, tz] = time.split(/(?=[+-])/);
        return `${months[Number(m)]} ${d} ${y} ${t} GMT${tz}`;
      };
      
      const dt = format('2013-07-18T17:00:00-05:00');
      console.log(dt);
      // Jul 18 2013 17:00:00 GMT-05:00

      有 JavaScript 和其他库方法可以让您将日期时间字符串转换为 Date 实例,然后如果您始终从一个或几个特定时区接收到在客户端很容易识别。以下是几个例子。

      toLocaleString 使您能够在特定时区显示日期,但并非所有浏览器都支持设置时区所需的 options 参数(截至本答案日期)。例如(请注意,仍然不鼓励使用 Date 构造函数解析日期字符串,但大多数现代浏览器将处理如下所示的 ISO 8601 格式字符串):

      const dt = new Date('2013-07-18T17:00:00-05:00');
      const ny = dt.toLocaleString('en-US', { timeZone: 'America/New_York' });
      console.log(`Local: ${dt}`);
      console.log(`New York: ${ny}`);

      您还可以使用Moment.jsMoment Timezone 来显示特定时区的日期。例如:

      const ny = moment('2013-07-18T17:00:00-05:00').tz('America/New_York').format();
      console.log(`New York: ${ny}`);
      <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>

      在 JavaScript 中使用日期时间字符串和时区时,请务必注意以下事项。 JavaScript Date 构造函数不会更改时区偏移量。在问题示例中,当您使用 ISO 8601 格式从字符串创建日期时,Date 会执行以下操作:

      创建一个 JavaScript Date 实例,它代表一个单一的时刻 时间。日期对象使用 Unix 时间戳,一个整数值,即 自 1970 年 1 月 1 日 UTC 以来的毫秒数。

      换句话说,JavaScript Date 实例不存储(或更改)时区偏移量。您经常在本地时区看到来自 JavaScript Date 的输出的原因是 toString 是当您将 Date 实例记录到控制台(或使用各种其他方法来输出您的日期)时调用的默认方法。在大多数浏览器实现中,此方法依赖于浏览器的本地时区,将自 1970 年 1 月 1 日 UTC 以来的毫秒数转换为日期的字符串表示形式。

      【讨论】:

        【解决方案5】:

        不知道这是否会有所帮助:

        function goAheadMakeMyDate(s){
          var d = new Date(s);
          // override Date.toString()
          d.toString = function(){ return ''+s; };
          return d;
        }
        
        var example = goAheadMakeMyDate("Fri 19 July 2013 12:00:00 GMT");
        
        example.toString() // returns string actually used to construct the date
        'Fri 19 July 2013 12:00:00 GMT'
        
        example.toLocaleString()
        'Fri Jul 19 2013 08:00:00 GMT-0400 (EDT)'
        
        1*example // gives seconds since epoch
        1374235200000
        

        根据您的意见:

        example = goAheadMakeMyDate('2013-07-18T17:00:00-05:00')
        { Thu, 18 Jul 2013 22:00:00 GMT toString: [Function] }
        > example.toString()
        '2013-07-18T17:00:00-05:00'
        > example.toLocaleString() // I live in GMT-4
        'Thu Jul 18 2013 18:00:00 GMT-0400 (EDT)'
        > 1*example  // convert to integer date
        1374184800000
        

        但是,如果您开始修改此日期,toString 将不会更改并会咬你。

        【讨论】:

        • 这使我的日期:-) 但是当日期对象被修改(setHour 或其他东西)时它将不起作用。
        • 但是你开了 5 枪,还是你的第 6 枪?实际上,正确执行此操作可能需要复制 date 所做的所有内容...
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-23
        • 1970-01-01
        • 2012-10-23
        • 2014-12-28
        • 1970-01-01
        相关资源
        最近更新 更多