javascript 解析 ISO 8601 日期字符串时如何假设本地时区?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15517024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 01:03:44  来源:igfitidea点击:

How to assume local time zone when parsing ISO 8601 date string?

javascript

提问by CrazyNooB

I have a ISO date string as below

我有一个 ISO 日期字符串,如下所示

 var startTimeISOString = "2013-03-10T02:00:00Z";

when I convert it to date object in javascript using below code, it returns

当我使用下面的代码将它转换为 javascript 中的日期对象时,它返回

var startTimeDate = new Date(startTimeISOString);

output is

输出是

Date {Sun Mar 10 2013 07:30:00 GMT+0530 (India Standard Time)}

It sure converts the ISOStringto date but it converts to local time since new Date()is client dependent. How to just convert iso date time string to date and time but not to local date-time..?

它确实将ISOString转换为日期,但由于new Date()依赖于客户端,因此它会转换为本地时间。如何将iso日期时间字符串转换为日期和时间而不是本地日期时间..?

Thanks

谢谢

回答by CrazyNooB

According to MDN:

根据 MDN

Differences in assumed time zone

Given a date string of "March 7, 2014", parse() assumes a local time zone, but given an ISO format such as "2014-03-07" it will assume a time zone of UTC. Therefore Date objects produced using those strings will represent different moments in time unless the system is set with a local time zone of UTC. This means that two date strings that appear equivalent may result in two different values depending on the format of the string that is being converted (this behavior is changed in ECMAScript ed 6 so that both will be treated as local).

假设时区的差异

给定日期字符串“2014 年 3 月 7 日”,parse() 假定本地时区,但给定 ISO 格式(例如“2014-03-07”)它将假定时区为 UTC。因此,使用这些字符串生成的 Date 对象将代表不同的时刻,除非系统设置为 UTC 的本地时区。这意味着两个看起来相等的日期字符串可能会产生两个不同的值,具体取决于正在转换的字符串的格式(此行为在 ECMAScript ed 6 中发生了更改,因此两者都将被视为本地)。

I have done like this and am now getting the exact time which is inside the ISO date string instead of the local time

我已经这样做了,现在我得到了 ISO 日期字符串中的确切时间,而不是本地时间

 var startTimeISOString = "2013-03-10T02:00:00Z";

 var startTime = new Date(startTimeISOString );
 startTime =   new Date( startTime.getTime() + ( startTime.getTimezoneOffset() * 60000 ) );

This will give the same date time inside iso date string , the output here is

这将在 iso 日期字符串中给出相同的日期时间,这里的输出是

o/p

o/p

Date {Sun Mar 10 2013 02:00:00 GMT+0530 (India Standard Time)}

回答by RobG

To sum up the conversation from tracevipin's post:

总结一下 tracevipin 帖子中的对话:

All Date objects are based on a time valuethat is milliseconds since 1970-01-01T00:00:00Z so they are UTC at their core. This is different to UNIX, which uses a value that is represents seconds since the same epoch.

所有 Date 对象都基于自 1970-01-01T00:00:00Z 以来的毫秒时间值,因此它们的核心是 UTC。这与 UNIX 不同,UNIX 使用表示自同一纪元以来的秒数的值。

The Date.prototype.toStringmethod returns an implementation dependent string that represents the time based on the system settings and timezone offset of the client (aka local time).

Date.prototype.toString方法返回表示基于客户端(又名当地时间)偏移的系统设置和时区的时间依赖于实现的字符串。

If a UTC ISO8601 time string is required, the Date.prototype.toISOStringmethod can be used. It's quite easy to write a "shim" for this methods if required.

如果需要 UTC ISO8601 时间字符串,可以使用Date.prototype.toISOString方法。如果需要,很容易为这种方法编写一个“垫片”。

Lastly, do not trust Date.parseto parse a string. Support for an ISO8601 format UTC string is specified in ES5, however it's not consistently implemented across browsers in use. It is much better to parse the string manually (it's not hard, there are examples on SO of how to do it) if wide browser support is required (e.g. typical web application).

最后,不要相信Date.parse来解析字符串。ES5 中指定了对 ISO8601 格式 UTC 字符串的支持,但是它在使用的浏览器中并没有一致地实现。如果需要广泛的浏览器支持(例如典型的 Web 应用程序),最好手动解析字符串(这并不难,有关于如何做的示例)。

Simple ISO8601 UTC time stamp parser:

简单的 ISO8601 UTC 时间戳解析器:

function dateObjectFromUTC(s) {
  s = s.split(/\D/);
  return new Date(Date.UTC(+s[0], --s[1], +s[2], +s[3], +s[4], +s[5], 0));
}

and here's a shim for toISOString:

这是 toISOString 的垫片:

if (typeof Date.prototype.toISOString != 'function') {

  Date.prototype.toISOString = (function() {

    function z(n){return (n<10? '0' : '') + n;}
    function p(n){
      n = n < 10? z(n) : n;
      return n < 100? z(n) : n;
    }

    return function() {
      return this.getUTCFullYear() + '-' +
             z(this.getUTCMonth() + 1) + '-' +
             z(this.getUTCDate()) + 'T' +
             z(this.getUTCHours()) + ':' +
             z(this.getUTCMinutes()) + ':' +
             z(this.getUTCSeconds()) + '.' +
             p(this.getUTCMilliseconds()) + 'Z';
    } 
  }());
}

回答by Diode

This happens because date is printed using toStringmethod which by default returns the date and time in local timezone. The method toUTCStringwill give you the string you need.

发生这种情况是因为日期是使用toString方法打印的,该方法默认返回本地时区的日期和时间。该方法toUTCString将为您提供所需的字符串。

Dateactually keeps the date as unix time in milliseconds and provides methods to manipulate it.

Date实际上将日期保持为以毫秒为单位的 unix 时间并提供操作它的方法。

回答by Ed Sykes

In vanilla javascript there isn't a way to create a date that assumes the local time of the ISO formatted string you give it. Here's what happens when you pass an ISO 8601 formatted string to javascript. I'm going to use a non UTC time as it illustrates the problem better than using an ISO formatted string:

在 vanilla javascript 中,没有办法创建假定您提供的 ISO 格式字符串的本地时间的日期。这是将 ISO 8601 格式的字符串传递给 javascript 时会发生的情况。我将使用非 UTC 时间,因为它比使用 ISO 格式的字符串更能说明问题:

  1. var startTime = new Date("2013-03-10T02:00:00+06:00"). Note this could also be 2013-03-10T02:00:00Zor any other ISO-formatted string.
  2. read the time, apply the offset and calculate milliseconds since 1970-01-01T00:00:00Z
  3. You now have only milliseconds - you have lost all timezone info. In this case 1362859200000
  1. var startTime = new Date("2013-03-10T02:00:00+06:00"). 请注意,这也可以是2013-03-10T02:00:00Z或任何其他 ISO 格式的字符串。
  2. 读取时间,应用偏移量并计算自 1970-01-01T00:00:00Z 以来的毫秒数
  3. 您现在只有几毫秒 - 您已经丢失了所有时区信息。在这种情况下 1362859200000

All functions, apart from the ones that give you a UTC representation of that number, will use the timezone of the computer running the code to interpret that number as a time.

除了为您提供该数字的 UTC 表示的函数之外,所有函数都将使用运行代码的计算机的时区将该数字解释为时间。

To do what the original poster wants, you need to.

为了做原始海报想要的,你需要做。

  1. parse the ISO string, interpret the offset ('Z' or '+06:00') as the timezone offset
  2. store the timezone offset
  3. calculate and store the ms since epoch, using the offset timezone offset
  4. hold that offset
  5. whenever attempting to make a calculation or print the date, apply the timezone offset.
  1. 解析 ISO 字符串,将偏移量('Z' 或 '+06:00')解释为时区偏移量
  2. 存储时区偏移量
  3. 使用偏移时区偏移量计算并存储自纪元以来的毫秒数
  4. 保持该偏移量
  5. 每当尝试进行计算或打印日期时,请应用时区偏移量。

This isn't trivial, and requires a complete interpretation of the 8601 spec. Way too much code to put here.

这不是微不足道的,需要对 8601 规范进行完整的解释。太多的代码放在这里。

This is exactly what moment.jsis designed to do. I strongly recommend using it. Using moment.js:

这正是moment.js的设计目的。我强烈建议使用它。使用moment.js:

moment("2013-03-10T02:00:00Z").format()
"2013-03-10T02:00:00Z"

this will result in printing the ISO time of the original string, preserving the offset.

这将导致打印原始字符串的 ISO 时间,保留偏移量。