在JavaScript中创建新日期时的奇怪行为

时间:2015-12-04 05:41:22

标签: javascript google-chrome date ecmascript-6

我在JavaScript中使用Date对象,发现了一种非常奇怪的行为。

如果使用1个参数创建新日期并调用getFullYear方法,则返回的值比传入的值少1

new Date("2014").getFullYear()
=> 2013

为了测试一个理论,它会返回“2014-1-1”,而在前一个时区,前一年,我做了另一个测试。

new Date("2014").getDate()
=> 31

new Date("2014").getMonth()
=> 11

这将支持时区理论,但它仍然没有解释接下来的两个例子。

如果您输入字母数字字符串,您将获得正确的年份。它甚至适用于像这样的乱码

new Date("hsdkjfuweirsdf 2014").getFullYear();
=> 2014

对于第一个例子,我假设函数从0开始计数,因此年份将减少1。但是,这并不能解释为什么我的第二个函数返回正确的年份。

编辑:

我发现了new Date()构造函数的另一个奇怪行为。如果您传入多个参数,它也将返回正确的年份

new Date("2014", "9").getFullYear()
=> 2014

以上所有测试均在Google Chrome中多次完成。

2 个答案:

答案 0 :(得分:2)

在第一种情况下,日期字符串被检测为部分跟随一位官员Date Time String Format

  

ECMAScript根据ISO 8601扩展格式的简化为日期时间定义字符串交换格式。格式如下: YYYY-MM-DDTHH:mm:ss.sssZ

至少在第5版ECMAScript中,您的浏览器目前正在遵守:

  

缺席时区偏移的值为“ Z ”。

使用此功能,假定日期字符串为UTC / GMT时间进行解析。

Date.parse("2014") === Date.parse("2014-01-01T00:00:00Z");

然后,getFullYear()提供相同"时刻的年份"在您当地的时区,与其等效的UTC方法相比。

new Date("2014").getFullYear()    // 2013 (or 2014 for users in UTC+N timezones)
new Date("2014").getHours()       // (not 0, unless you live in UTC+0)

new Date("2014").getUTCFullYear() // 2014
new Date("2014").getUTCHours()    // 0

第二个例子,包括年前的乱码,不符合上述格式,甚至是部分格式。

由于这是规范中正式定义的唯一格式,浏览器现在是on its own to determine if and how it should parse the date string

  

如果String不符合[日期时间字符串格式],则该函数可以回退到任何特定于实现的启发式或特定于实现的日期格式。

并且,它默认选择使用您当地的时区,并且在很大程度上忽略了乱码。

new Date("hsdkjfuweirsdf 2014").getFullYear() // 2014
new Date("hsdkjfuweirsdf 2014").getHours()    // 0

注意:most recent, 6th edition of ECMAScript更改了缺少时区的日期字符串的假设值:

  

如果没有时区偏移,则将日期时间解释为当地时间。

答案 1 :(得分:1)

这肯定是Date解析UTC与本地时区的效果。

通常情况下,如果您提供任何可以"适合"到ISO 8601 format Date()构造函数会尝试解析位于GMT的对象。否则它将为您提供您自己的本地(使用您的浏览器的时区信息)对象。

// how many minutes to add to get GMT?
var tzOffset = new Date().getTimezoneOffset()
// 300    // Eastern Standard Time, GMT-5

// will be parsed as GMT:
var gmt = new Date("2011");

// what year is it for me?
gmt.getFullYear()
// 2010

这是格林威治标准时间2011年1月1日的当地年份。(当伦敦庆祝新年时,它仍然是纽约市的2010年)

值得注意的是,有UTC功能:

// what year is it in London?
gmt.getUTCFullYear()
// 2011

让我们看看当我们添加"小时,以便我们的当地时间赶上:

// add tzOffset, voila, "correct" year
var localyear = new Date(gmt.getTime() + tzOffset*60*1000).getFullYear()
// 2011

此外,Chrome会做出最好的努力"解析垃圾(非标准)字符串。这是依赖浏览器的行为,依赖它需要您自担风险。这解释了"hsdkjfuweirsdf 2014"等字符串的本地时间定位行为。