momentJs解析日期:意外行为

时间:2015-10-01 14:56:30

标签: javascript date momentjs

使用momentJs我发现了一些我不理解的东西; 让我们来讨论一个特定的日期,例如2099-11-11T15:00

将时刻转换为日期:

> moment('2099-11-11T15:00').toDate()  
// => Wed Nov 11 2099 15:00:00 GMT+0100 (CET)

将日期转换为时刻:

> var d = new Date('2099-11-11T15:00')  
// => undefined  
> moment(d)  
// => { ... _d: Wed Nov 11 2099 16:00:00 GMT+0100 (CET) }

我们有不同的日期,第一个是星期三15:00,但第二个星期三是16:00。确实,如果我们比较它们:

moment(d).isSame(moment('2099-11-11T15:00'))
// => false

初看起来,我认为这与toDate()方法有关,但并非如此;让我们输入以下内容:

new Date('2099-11-11T15:00').toISOString()
'2099-11-11T15:00:00.000Z'
moment('2099-11-11T15:00').toISOString()
'2099-11-11T14:00:00.000Z'

这里发生了什么?

2 个答案:

答案 0 :(得分:2)

一些事情:

  • 不要关注_d字段。未标记的字段是moment的API内部,可能并不总是您期望的。在许多函数中,必须结合其他内部字段(例如_offset)进行评估,以生成有效输出。相反,请使用各种公共功能,例如formattoDate.valueOf等。

  • 认识到Date构造函数如何解析字符串以及时刻的解析函数如何工作之间存在许多差异。不要指望它们匹配。

  • 当字符串不包含任何时区信息时,moment(...)将始终视为本地信息,而moment.utc(...)则将其视为UTC。 (你的答案就是一个很好的例子。)

  • Date构造函数被赋予字符串时,字符串的格式会显着影响解释。实际行为可能因实现而异,但大多数当前浏览器会看到连字符,T表示字符串是ISO8601格式。但是,如果没有任何尾随Z或偏移量,ES5规范会将其解释为UTC。这已经改变了ES6,它将这些情况视为本地时间 - 以更好地符合ISO8601规范。由于不清楚各种环境何时会开始实施此更改,因此谨慎不要依赖Date构造函数。

  • 如果您希望Date构造函数将您的值解释为 local 时间(使用ES5),则一种方法是使用字符串替换来删除T并使用斜杠(-)交换连字符(/)。这适用于大多数环境,但没有相关规范。 (我被告知在一些Safari浏览器中它失败了。)实际上,我只是使用Moment的解析函数,而不是完全依赖Date构造函数。

答案 1 :(得分:1)

最后我决定对每个操作使用moment.utc(...)而不是moment(),这样做,两次都是相同的:

var d = new Date('2099-11-11T15:00')
var m = moment.utc('2099-11-11T15:00')
m.isSame(moment.utc(d))
// => true