简体   繁体   中英

momentJs parse Date: Unexpected behaviour

Using momentJs I've come across something I don't understand; let's play around with one particular date, for example 2099-11-11T15:00

Convert Moment to Date:

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

Convert Date to Moment:

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

We have different dates , the first one is wednesday at 15:00 but the second one is wednesday at 16:00. Indeed if we compare them:

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

At first look I thought it was something related with toDate() method but it's not; let's type the following:

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'

What's going on here?

A few things:

  • Do not pay attention to the _d field. Underscored fields are internal to moment's API, and may not always be what you expect. In many functions, it has to be evaluated in combination with other internal fields (such as _offset ) in order to produce a valid output. Instead, use the various public functions, such as format , toDate , .valueOf , and others.

  • Recognize there are many difference between how the Date constructor parses strings and how moment's parsing functions work. Don't expect them to match.

  • When a string doesn't contain any time zone information, moment(...) will always treat it as local, while moment.utc(...) will treat it as UTC. (Your answer gives a good example of that.)

  • When the Date constructor is given a string, the format of the string can affect the interpretation significantly. The actual behavior can vary across implementations, but most current browsers will see the hyphens and the T as an indication that the string is in ISO8601 format. However without any trailing Z or offset, the ES5 spec says to interpret those as UTC. This has changed for ES6, which will treat those cases as local time - to better conform with the ISO8601 spec. Since it's not clear when various environments will start to implement this change, it's prudent to not rely on the Date constructor.

  • If you wanted the Date constructor to interpret your value as local time (with ES5), one approach is to use string replacements to remove the T and swap the hyphens ( - ) with slashes ( / ). This works in the majority of environments, though there is no specification around this. (I've been told it fails in some Safari browsers.) Really, I would just use Moment's parsing functions, and not rely on the Date constructor at all.

Finally I decided to use moment.utc(...) instead of moment() for every operation, doing so, both times are the same:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM