Javascript: `new Date(dateString)`与`new Date(year, month, day)`的区别

4

参考这个问题的已接受答案:如何在JavaScript中获取两个日期之间的天数?。我看到,在parseDate函数中:

function parseDate(str) {
    var mdy = str.split('/')
    return new Date(mdy[2], mdy[0]-1, mdy[1]);
}

他正在做这件事情:
var mdy = str.split('/')
return new Date(mdy[2], mdy[0]-1, mdy[1]);

即将传递的日期按月、日和年分割,然后将其传递给Date,例如new Date(year, month, day),而实际上他可以直接使用new Date(str),它会返回相同的结果(是吗?)。有人可以解释一下两种方式之间的区别吗?
更新:测试结果:
var str = '1/1/2000'
var mdy = str.split('/')
console.log( new Date(str) ) // Sat Jan 01 2000 00:00:00 GMT+0500 (Pakistan Standard Time)
console.log( new Date(mdy[2], mdy[0]-1, mdy[1]) ); // Sat Jan 01 2000 00:00:00 GMT+0500 (Pakistan Standard Time)

1
不,它们并不相同,即使你稍后减去一个月(他正在执行mdy[0]-1),因为新的Date(str)需要(按标准)仅接受特定格式的日期(年/月/日,请参见此帖子),而且他们使用了特定语言环境规则进行解析(月/日/年)。老实说,我甚至不会使用该代码进行解析(因为是的,对于不同的语言环境,它实际上会出错)。 - Adriano Repetti
根据您的更新:如果您使用1/1/200,那么您不会看到任何差异,但是浏览器在解析日期时只能接受它转换为字符串后产生的yyyy/mm/dd格式。尝试一下13/1/2014...这取决于所在地区(对于月份在前的区域,它将失败)。 - Adriano Repetti
@LearningNeverStops 是的,因为你的语言环境与他们使用手动解析的方式相匹配。例如,在我的语言环境(意大利/意大利),它将失败,因为我们写日/月/年(然后,“2014年12月21日”是“21/12/2014”,但他们的解析程序期望“12/21/2014”,转换显然会失败)。通常我强烈建议不要在JavaScript中手动进行日期解析,这是一个复杂的主题,有一些非常好的库可供使用。 - Adriano Repetti
2个回答

1
不,它们不同(即使假设您稍后减去一个月:他正在执行mdy [0] - 1),因为按照标准要求,new Date(str)仅接受特定格式的日期 ISO 8601(YYYY-MM-DDTHH:mm:ss.sssZ,也请参见this post,我这里不再重复):

如果字符串不符合ISO 8601格式,则该函数可能会回退到任何实现特定的启发式算法或实现特定的日期格式。

请注意(如评论中Royi所指出的),RFC 2822也应该被支持(根据MDN),但它在JavaScript规范中没有提到,而且Internet Explorer不正式支持它(参见MSDN,它可以解析类似的内容,但并非完全相同)。
在那段代码中,他们使用特定的区域设置规则进行解析(我猜是 en-US 区域设置的 MM/DD/YYYY,但不仅限于这个)。老实说,我甚至不会使用那段代码进行解析(因为实际上,它会因为不同的区域设置而出错:即使用于分割的分隔符也不是"区域设置安全的")。让我举个例子来解释一下:
  • 如果您使用了正确配置的日期时间选择器(或在支持的情况下使用 <input type="date"/>),您将按照本地区域设置输入日期。例如,在意大利(但通常在欧洲),我们写成 DD/MM/YYYY
  • 现在让我们假设用户选择了2014年12月21日(根据他所在地区的格式为21/12/2014)。
  • 通过字符串分割,代码会失败(因为它会把21作为月份数字,显然这是无效的)。更糟糕的是,这种错误甚至可能不被注意到(例如,如果用户选择1/2/2014,代码将“认为”它是1月2日,但用户选择的是2月1日)。你想让它变得更复杂吗?即使new Date(str)也可能失败,因为它取决于浏览器(您无法真正相信启发式算法是可移植和安全的)。
如果你在问自己,“那么为什么他们使用这样的代码?”我会说,他们使用了一种快速解决方案来支持使用 en-US 语言环境的日期(可能是因为他们使用的浏览器无法通过启发式猜测支持它们),但这不是你应该重复使用的东西。
解决方案?除非你真正深入了解自己在做什么,否则永远不要手动解析日期,而是使用一个好的库(例如 moment.js)来处理,因为你可能对日期格式化做出的大多数假设都是...错误的

@RoyiNamir 严格来说(请参见标准中引用的段落),解析 ISO 8601 是必须的,它可能会退回到[...]。这就是为什么我写了"必须",但我也发布了引用。该格式在大多数浏览器上都可以使用(据我所知),但它不是标准格式,而且在所有旧版浏览器中都不受支持... - Adriano Repetti
同时:_dateString是一个字符串,表示RFC2822ISO 8601日期(也可以使用其他格式,但结果可能出乎意料)_,因此它也可以处理rfc支持。 - Royi Namir
@RoyiNamir 但是 RFC2822 在 IE 中不被支持(我承认这并不令人惊讶):MSDN(请参见“其他数据格式”部分),而且它在 JavaScript 规范中也没有提到 - Adriano Repetti
http://chat.stackoverflow.com/rooms/61331/room-for-royi-namir-and-adriano-repetti - Royi Namir
@Bergi 是的,可能所有主要浏览器都支持它,但我会避免使用它,因为如果用户编写(或我们构建字符串)“1/2/2015”,那么就有太多的启发式方法了。什么样的浏览器会理解?是众所周知的“MM/DD/YYYY”还是本地化的“DD/MM/YYYY”?对于像现在这样的两位数年份,“12/1/14”是什么意思?在我看来,不确定性太大了,即使它在我们的浏览器和我们的语言环境中工作,我们也无法预测另一个浏览器甚至只是另一个语言环境会发生什么... - Adriano Repetti
显示剩余6条评论

-1

我尝试将你的测试代码输入到jsperf.com中,在我的机器上得出了明确的结果,它们表明你不应该尝试拆分字符串。

我尝试使用拆分字符串进行了两次测试,令人惊讶的是,拆分本身并不是占用时间的原因。

请在http://jsperf.com/date-from-string-or-dateparts上亲自尝试。


1
这不是关于时间的问题(一般来说,我会选择更清晰简洁的方式,用户在这样的代码中不会注意到任何差异),而是正确性的问题... - Adriano Repetti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接