2013-03-20 76 views
21

我有一个ISO日期字符串如下如何在解析ISO 8601日期字符串时假定本地时区?

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

当我使用它转换成日期对象在JavaScript下面的代码,则它返回

var startTimeDate = new Date(startTimeISOString); 

O/P是

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

它确实将ISOString转换为日期,但它转换为LO校准时间,因为新的Date()是依赖于客户端的。如何将ISO日期时间字符串转换为日期和时间,但不是本地日期时间..?

由于

+1

您的ISO时间以'Z'开头,即UTC(格林威治标准时间)。如果时间实际上是从本地开始的,则应将“Z”替换为“+0530”。但是如果你想循环访问你的时间,你应该保持UTC格式的字符串版本。 – 2014-04-11 15:58:04

+0

您能澄清一下,您正在尝试创建一个保留原始时区的字符串表示形式(在本例中为祖鲁语(Z)),而不是重新解释运行代码的计算机时区中的时间。这听起来像你,但它不是100%清楚。 – 2015-07-10 08:00:29

回答

44

According to MDN:在假定的时区

差异

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

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

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

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

内这将会给ISO日期字符串中相同的日期时,这里输出是

O/p

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

我没有看到解析函数的细节与此有关。引用的MDN段落只是指出,解析查看字符串的格式并确定格式是RFC2822还是ISO8601。 – 2015-07-10 08:05:31

+0

答案在这里给出了一天的正确时间,但这很危险,因为你仍然处于与原始时间不同的时区。正确答案会创建一个与原始时间相同的日期对象。 – 2015-07-10 08:11:41

+0

请注意,getTimezoneOffset是UTC与本地之间的差异,产生与人们预期相反的结果。从MDN开始:“请注意,这意味着如果本地时区在UTC之后,则偏移量为正值,如果超前,则为负值。例如,如果您的时区为UTC + 10(澳大利亚东部标准时间),则返回-600 。“ – 2015-07-10 08:19:27

5

这是因为日期采用toString方法,其默认返回在本地时区的日期和时间打印。方法toUTCString会给你你需要的字符串。

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

+0

我可以将它作为日期对象而不是字符串吗?现在它返回一个字符串,但我需要它是一个日期对象,因为我正在与其他日期进行日期比较 – CrazyNooB 2013-03-20 07:14:34

+0

由于日期对象存储unix时间,您可以在任何需要的地方使用UTC方法。请参阅Date中的UTC方法:https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Date – Diode 2013-03-20 07:16:27

+0

getUTCDate,getUTCMonth等 – Diode 2013-03-20 07:17:06

9

从tracevipin的帖子总结的对话:

所有Date对象是基于time value是毫秒,因为1970-01-01T00:00:00Z所以他们UTC其核心。这与UNIX不同,UNIX使用自相同历元以来代表秒的值。

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

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

最后,不要相信Date.parse来解析字符串。支持ISO8601格式的UTC字符串是在ES5中指定的,但是它在所使用的浏览器中并不一致。如果需要广泛的浏览器支持(例如典型的Web应用程序),手动解析字符串要好得多(这并不困难,例如如何操作)。

简单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)); 
} 

,这里是为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'; 
    } 
    }()); 
} 
+0

这样的库来实现。你应该把你的正则表达式改为'/ [\ - \。\ +:TZ]/g' – 2014-02-23 22:57:48

+0

@OnurYıldırım - 你是对的,它没有正确分割字符串,最简单的RegExp是'/ \ D /'。它不是作为一个通用的ISO 8601字符串分析器,这是一个非常大的工作。 – RobG 2014-02-23 23:44:17

+0

ISO字符串和UTC是两个不同的东西。这不会产生ISO 8601字符串。 ISO 8601编码的时区,这不会(由于使用getUTC ...) – 2015-07-10 08:14:42

1

在香草javascript没有办法创建一个假定您给它的ISO格式字符串的本地时间的日期。以下是将ISO 8601格式的字符串传递给javascript时发生的情况。我打算使用非UTC时间,因为它比使用ISO格式的字符串更好地说明了问题:

  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

除了那些给出UTC编号的代码之外,所有函数都将使用运行代码的计算机的时区来解释该数字的时间。

要做什么原始海报想要的,你需要。

  1. 解析ISO串,解释偏移(“Z”或“06:00”)作为时区偏移
  2. 存储中的时区偏移
  3. 计算和MS存储纪元以来,使用偏移时区偏移量
  4. 保持该偏移量
  5. 每当尝试进行计算或打印日期时,应用时区偏移量。

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

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

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

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

相关问题