moment.date($day).month($month).year($year) behaves different than moment([$year, $month, $date])

Created on 2 Nov 2015  ·  4Comments  ·  Source: moment/moment

The date is parsed differently using these two setter methods.
When setting the date to October 31, 2015. The chained method returns 2015-10-01 while the init method returns 2015-10-31

var year = 2015;
var month = 9; //october
var day = 31;

console.log(moment().date(day).month(month).year(year).format('YYYY-MM-DD'));
//2015-10-01

console.log(moment([year, month, day]).format('YYYY-MM-DD'));
//2015-10-31

JS Fiddle: http://jsfiddle.net/dgnjer7z/

Most helpful comment

Note that this

$('#chained').val(moment().year(2015).month(9).date(31).format('YYYY-MM-DD'));

properly returns 2015-10-31

In fact moment mimics the behavior of JS date object.

First you create moment() that gives you current date (November 3rd as of today). You try to set its day to 31 but November has only 30 days, so JS native date object "intelligently" adds one day and moves date to 1st December (you can set day to any crazy number, like 42, and JS will do an arithmetic by adding a proper number of days and rewinding month and year if needed, not the best practice, it would have been better if it was throwing).

The solution is to always set year, month, day, hour, minute, in this order to avoid issues like this.

All 4 comments

Note that this

$('#chained').val(moment().year(2015).month(9).date(31).format('YYYY-MM-DD'));

properly returns 2015-10-31

In fact moment mimics the behavior of JS date object.

First you create moment() that gives you current date (November 3rd as of today). You try to set its day to 31 but November has only 30 days, so JS native date object "intelligently" adds one day and moves date to 1st December (you can set day to any crazy number, like 42, and JS will do an arithmetic by adding a proper number of days and rewinding month and year if needed, not the best practice, it would have been better if it was throwing).

The solution is to always set year, month, day, hour, minute, in this order to avoid issues like this.

The fact about overflow handling is indeed documented:

http://momentjs.com/docs/#/get-set/date/

Gets or sets the day of the month.

Accepts numbers from 1 to 31. If the range is exceeded, it will bubble up to the months.

Though the behavior in the corner case like yours is indeed surprising.

I opened a PR in documentation repo the explains this common issue
https://github.com/moment/momentjs.com/pull/244

Yeah, I'm not sure this is fixable. Moment doesn't know that you're going to set the month, so it tries to set the day on the current month, which may or may not have a 31. It's ignorant of your intensions. I think @jakub-g's doc PR is good; let's do that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vbullinger picture vbullinger  ·  3Comments

slavafomin picture slavafomin  ·  3Comments

benhathaway picture benhathaway  ·  3Comments

Shoroh picture Shoroh  ·  3Comments

paulyoung picture paulyoung  ·  3Comments