新date(“2017-01-01”)和新date(“2017-1-1”)之间有什么区别?

我在chrome控制台inputnew Date("2017-01-01") ,输出显示其小时为8,但是new Date("2017-01-1")new Date("2017-1-01")显示他们的小时都是0,那么new Date(dateString)如何parsing呢?

 new Date("2017-01-01") // Sun Jan 01 2017 08:00:00 GMT+0800 (中国标准时间)* new Date("2017-01-1") // Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)* new Date("2017-1-1") // Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)* new Date("2017-1-01") // Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)* 

“2017-01-01”遵循ISO标准 ES5date时间string格式(简化ISO 8601扩展格式) ,因此是UTC时间,即中国上午8点。 所有其他string在Chrome 1中被parsing为本地时间。


1 Chromium中的相关源代码: https : //cs.chromium.org/chromium/src/v8/src/dateparser-inl.h? type = cs & l = 16

Chromium中的date分析遵循标准的ES5规则以及这些额外的规则:

  • 第一个数字之前的任何无法识别的单词都将被忽略。
  • 括号文字被忽略。
  • 一个无符号的数字后跟:是一个时间值,并被添加到TimeComposer 。 一个数字后跟::增加了第二个零。 一个数字紧跟着. 也是一个时间,必须以毫秒为单位。 任何其他号码是一个date组件,并添加到DayComposer
  • 一个月份名称(或者真的:任何具有与三个月份相同的前三个字母的单词)在Day composer中被logging为指定的月份。
  • 一个可识别为时区的单词被logging为(+|-)(hhmm|hh:)
  • 旧版date不允许在读取数字(在第一个数字之前,允许任何垃圾)之后使用额外的符号( +- )或不匹配)。
  • 任何满足ES5规则和上述规则的string都将使用ES5规则进行分析。 这意味着"1970-01-01"将在UTC时区不在本地时区。

那是什么意思?

首先请注意,“2017-01-01”是以UTC时间进行分析的,因为它是“date”string而不是“date时间”string,它与“date”string的ES5定义相匹配。 如果附加时间,那么它将遵循ISO标准并在当地时间进行parsing。

例子:

  • 2017-01-01 – 2017年1月1日,UTC时间
  • 2017-01-01T00:00 – 2017年1月1日在当地时间
  • 2017-1-1 – 2017年1月1日在当地时间
  • 2017-(hello)01-01 – 2017年1月1日在当地时间
  • may 2017-01-01 – 2017年5月1日在当地时间
  • mayoooo 2017-01-01 – 2017年5月1日在当地时间
  • "jan2017feb-mar01apr-may01jun" – 2017年6月1日在当地时间

新date(“2017-01-01”)和新date(“2017-1-1”)之间的差异

new Date("2017-01-01")是在规范(更多下面)。 new Date("2017-1-1")不是,所以JavaScript引擎想要应用的任何“…特定实现的启发式或特定于实现的date格式”都会落后。 例如,你不能保证如何(或是否)它将成功parsing,如果是的话,是否将被parsing为UTC或本地时间。

虽然new Date("2017-01-01")是规范的,可惜的是浏览器应该做什么,它已经成为一个移动的目标,因为它没有时区指标:

  • 在ES5 (2009年12月)中,没有时区指示符的string应该被parsing为UTC。 但是这与date/时间格式所基于的ISO-8601标准不一致,即没有时区指示符的string应该是本地时间,而不是UTC。 所以在ES5中, new Date("2017-01-01")在UTC中被parsing。
  • 在ES2015 (又名ES6,2015年6月)中,没有时区指示符的string应该是本地时间,而不是UTC,如ISO-8601。 所以在ES2015中, new Date("2017-01-01")被parsing为当地时间。
  • 但是 , 在ES2016 (2016年6月)中又一次发生了变化,因为浏览器一直在parsing仅有date的表单,而且这些表单在UTC中是多年的。 因此,从ES2016开始, 仅使用date格式(如"2017-01-01" )以UTC格式parsing,但在当地时间parsingdate/时间格式(如"2017-01-01T00:00:00" )。

可悲的是,并非所有的JavaScript引擎目前都实现了这个规范。 Chrome(截至撰写本文,为v56)以UTC分析date/时间表格,即使它们应该是本地时间(IE9也是如此)。 但是,Chrome,Firefox和IE11(我没有IE10或Edge)都能正确处理date格式(如UTC)。 IE8完全不实现ISO-8601格式(在ES5规范发布之前已经发布)。

当parsingdate时,JavaScript将ISOdate解释为UTC时间和其他格式为本地时间。

正如MDN文章所言,

如果string仅为ISO 8601date,则UTC时区用于解释参数。

给定一个“2014年3月7日”的datestring,parse()假定一个本地时区, 但是给定一个ISO格式,例如“2014-03-07”,它将假设一个UTC时区(ES5和ECMAScript 2015) 。 因此,使用这些string生成的Date对象可能表示不同时刻,具体取决于支持的ECMAScript版本,除非系统设置为UTC本地时区。 这意味着两个显示等同的datestring可能会导致两个不同的值,具体取决于正在转换的string的格式。

 // 2017-03-28 is interpreted as UTC time, // shown as 2017-03-28 00:00:00 in UTC timezone, // shown as 2017-03-28 06:00:00 in my timezone: console.log("ISO dates:"); var isoDates = [new Date("2017-03-28")]; for (var dt of isoDates) { console.log(dt.toUTCString() + " / " + dt.toLocaleString()); } // Other formats are interpreted as local time, // shown as 2017-03-27 18:00:00 in my timezone, // shown 2017-03-28 00:00:00 in my timezone: console.log("Other formats:"); var otherDates = [new Date("2017-3-28"), new Date("March 28, 2017"), new Date("2017/03/28")]; for (var dt of otherDates) { console.log(dt.toUTCString() + " / " + dt.toLocaleString()); } 

这种格式是国际标准(ISO格式)

 new Date("2017-01-01") 

这保证了所有浏览器的相同输出。

但是,其他格式可能会根据浏览器而改变,因为它们没有很好的定义。

正如你可以看到这种格式

 new Date("2017-1-1") 

在Chrome中成功parsing,但在IE 11中出错