The problem is the order in which you're setting the fields. For each field, the Date object tries to make your number work. Since most months don't have 31 days, whatever month the Date has at that moment determines what it does with that 31 value. For instance, as I write this it's November, so new Date gives us a date in November. Calling setDate(31) will set the date to December 1st, because the Date object tries to make 31 work even though November has only 30 days. If it were currently February in a non-leap year, setDate(31) would set the date to March 3rd.
Instead, use new Date with Date.UTC:
var d1 = new Date(Date.UTC(2017, 9, 31)); // All the others will default to 0
Live example:
// Your way var d1 = new Date(); d1.setUTCMilliseconds(0); d1.setUTCSeconds(0); d1.setUTCMinutes(0); d1.setUTCHours(0); d1.setUTCDate(31); d1.setUTCMonth(9); //9 is october d1.setUTCFullYear(2017); console.log("Your way:"); console.log(d1.toISOString()); // Using new Date(Date.UTC(...)) instead: d1 = new Date(Date.UTC(2017, 9, 31)); console.log("Using new Date(Date.UTC(...)) instead:"); console.log(d1.toISOString());
If you had to do it with individual calls for some reason, you'd want to set the day-of-month to 1 (since, as you say in a comment, if it just happened to be 31, setting the month to November would result in Dec 1st!), and then set the fields in order largest unit to smallest unit: Year, month, day, hour, minute, second, ms:
d1 = new Date(); d1.setUTCDate(1); d1.setUTCFullYear(2017); d1.setUTCMonth(9); //9 is october // ...and so on in order largest unit to smallest unit
Live example:
// Setting them in order: Year, month, day, hour, minute, second, ms var d1 = new Date(); d1.setUTCDate(1); d1.setUTCFullYear(2017); d1.setUTCMonth(9); //9 is october d1.setUTCDate(31); d1.setUTCHours(0); d1.setUTCMinutes(0); d1.setUTCSeconds(0); d1.setUTCMilliseconds(0); console.log("Setting them in order: Year, month, day, hour, minute, second, ms:"); console.log(d1.toISOString());