new Date() set to 31 december 2014 says 1st december instead

Solution 1:

The thing is, when you set a day first, you're still in the current month, so September. September has only 30 days so:

var dt = new Date(); /* today */
dt.setDate("31"); /* 1st Oct 2014 as should be by spec */
dt.setMonth("11"); /* 1st Dec 2014 */
dt.setFullYear("2014"); /* 1st Dec 2014 */

Solution 2:

setMonth should before setDate: (not safe for Months less than 31 days)

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

And setMonth's second parameter also could be used to set date.

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11, 31);


If no arguments are provided for the constructor, it will use the current date and time according to system settings.

So, using setMonth and setDate separately would still cause unexpected result.

If the values set are greater than their logical range, the value will be auto adjusted to the adjacent value.

For example, if today is 2014-09-30, then

var dt = new Date();
dt.setFullYear(2014); /* Sep 30 2014 */
dt.setMonth(1);       /* Mar 02 2014, see, here the auto adjustment occurs! */
dt.setDate(28);       /* Mar 28 2014 */

To avoid this, set the values using the constructor directly.

var dt = new Date(2014, 11, 31);

Solution 3:

It's because the first thing you do is

dt.setDate(31)

This sets the current date to 31. The current month is September which has 30 days, so it's wrapping it round.

If you were to print out the date after this point, it would say 1 October.

Solution 4:

Assuming your intent is to set year, month and date simultaneously you could use the longer date constructor:

new Date(year, month, day, hour, minute, second, millisecond);

[...]

If at least two arguments are supplied, missing arguments are either set to 1 (if day is missing) or 0 for all others.

So you would write:

var dt = new Date(2014, 11, 31);

As already established, setting one portion of date at a time can result in overflows:

var dt = new Date(2012, 1, 29); // Feb 29 2012
dt.setFullYear(2014);           // Mar 01 2014 instead of Feb 28 2014

Moreover, setting month before date can still cause unexpected overflow (answers that recommend changing the order of methods are incorrect):

var dt = new Date(2014, 0, 31); // Jan 31 2014
dt.setFullYear(2014);           // Jan 31 2014
dt.setMonth(1);                 // Mar 03 2014 instead of Feb 28 2014
dt.setDate(1);                  // Mar 01 2014

Solution 5:

The why of the behaviour and how to avoid it has been amply explained.

But the real error in your code is that you shouldn't use the default constructor: new Date(). Your code will result in a Date on Dec. 13 with the current time. I doubt this is what you want. You should use the Date constructor that takes year, month and day as parameters.