targetEndDate = new Date();
targetEndDate.setFullYear(endDate.getFullYear());
targetEndDate.setMonth(endDate.getMonth());
targetEndDate.setDate(endDate.getDate());
Even if the endDate is valid, this can fail, because today is the 31st, which doesn't exist in endDate's month.If you just did:
targetEndDate = createDate(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
// createDate is an intentional placeholder, I didn't want to double-check the actual syntax
you wouldn't pass through the transitional stage where you have the new month but today's day of the month, which is what causes the bug.In this case, using mutation on the individual fields makes you have to transition through an invalid state to get back to a valid one, and the JS date object does something unexpected (though I think there's nothing good to do here, an exception is probably the best you could do). So mutation really is at issue here. In general, mutation creates room for these kind of counter-intuitive state transitions to arise.