类似的日期格式会产生意外的日期Javascript

时间:2017-04-20 14:30:21

标签: javascript date format

为什么第一个输入正常工作,但第二个输入在5小时前给出了一个结果?

new Date("2000-1-1")
Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
new Date("2000-01-01")
Fri Dec 31 1999 19:00:00 GMT-0500 (EST)

我怎样才能让第二个与我合作?



var a = new Date("2000-1-1"); // Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
var b = new Date("2000-01-01"); // Fri Dec 31 1999 19:00:00 GMT-0500 (EST)
console.log(a, a.getTime());
console.log(b, b.getTime());




2 个答案:

答案 0 :(得分:2)

MDN Date.parse()页面实际上描述了您看到这一点的原因(其中有许多正式支持的详细信息Date描述参数格式)。具体做法是:

  

假定时区的差异

     

如果日期字符串为“2014年3月7日”,则parse()会假定为本地时区,但如果采用ISO格式(如“2014-03-07”),则会假定UTC时区(ES5和ECMAScript) 2015年)。因此,使用这些字符串生成的Date对象可能代表不同的时刻,具体取决于ECMAScript支持的版本,除非系统设置了UTC的本地时区。这意味着两个看似等效的日期字符串可能会导致两个不同的值,具体取决于要转换的字符串的格式。

所以你所看到的是两件事的组合:

  1. 构造函数正在将您正确格式化的ISO日期值读取为UTC,因为没有提供时区,并且
  2. 准确识别您的本地计算机时区是美国东部,并正确调整值。
  3. 因此,您将看到2000年1月1日(UTC时间)(或1999年12月31日晚上7点)午夜的美国东部时区版本。

    由于你的第一个例子是使用非标准格式(来自JS的观点),所以第一个假设没有发挥作用,并且假设值的本地时区(特定于浏览器)创建值关于如何处理非标准格式的决定。)

答案 1 :(得分:0)

黄金法则永远不会使用Date构造函数或Date.parse解析字符串,因为它们在很大程度上依赖于实现。有许多怪癖。

根据ECMA-262,字符串" 2000-01-01"应该被解析为有效的ISO 8601仅限日期的表单but for timezone UTC+0000。像IE 8这样的旧浏览器可能根本不会解析它,有些可能会将其视为本地浏览器。

字符串" 2000-1-1"不是ISO 8601格式,因此浏览器可能会回归到他们喜欢的任何启发式,包括:

  1. 返回无效日期,因为它不是有效的ISO 8601日期格式
  2. 解析为2000年1月1日的本地日期
  3. 视为ISO 8601并解析为UTC + 0000
  4. 目前的浏览器中至少有1个和2个。

    因此,最好的办法是使用带解析器的库并提供字符串的格式,或者如果只有一种格式要处理,则编写一个简单的函数,例如

    
    
    /* Parse ISO 8601 date only form as local
    ** @param {string} s - string in format YYYY-M[M]-D[D]
    ** @returns {Date} If date parts out of range, returns invalid date
    */
    function parseISOLocal(s) {
      var b = s.split(/\D/);
      var d = new Date(b[0], --b[1], b[2]);
      return isNaN(d) || d.getMonth() != b[1]? new Date(NaN) : d;
    }
    
    ['2000-1-1','2000-01-01','2000-2-29','1900-2-29'].forEach(function(s) {
      console.log(s + ' : ' + parseISOLocal(s).toString());
    });