Doing Dumb Things with the Javascript Date Object

I ran into a weird (but, in retrospect, entirely predictable) problem generating dates. The code in question is supposed to kick in when the user is booking a resource for multiple days - this day each week for four weeks, this day each month for four months etc. Taking the interval and the number of occasions it is supposed to generate a list of dates.

Originally this code worked by calculating the number of milliseconds in a day, week or month and then adding it to today's date repeatedly. Before you point out that this is a completely dumb way of doing this I should mention that the Date object was only fully supported in IE4, and this code is probably old enough that this was significant &#59;) Anyway, the adding milliseconds approach fails whenever the sequence of dates crosses a change to or from British Summer Time, so I'd changed it to use the date object and then set the desired date using the standard methods. This worked much better in the BST case, but we started getting intermittent bug reports of strange things happening - whole months being missed in a sequence. Whenever we tried to replicate the issues, however, we didn't see a problem.

It was only when I happened to be doing some unrelated work on the same page on the 31st August that I finally realised what the problem was. Here is the code as it stood, see if you can spot the obvious problem:

var startDate = new Date;
startDate.setUTCFullYear(2000 + startDateYear);
startDate.setUTCMonth(startDateMonth);
startDate.setUTCDate(startDateDay);

Because startDate is always 'today' then on all months with 31 days in them setting the month to one with only 30 days in it is going to lead to a date like 31st September. At this point Javascript helpfully sets the date to the first of the next month (or the third, if you happen to be aiming for February). So, as I was actually busy with something else, I went for the easiest fix I could think of - switch the order of the setUTCMonth and setUTCDate lines:

var startDate = new Date;
startDate.setUTCDate(startDateDay);
startDate.setUTCMonth(startDateMonth);
startDate.setUTCFullYear(2000 + startDateYear);

It worked well enough for the 31st August case so I went with it.

Of course, that didn't really fix anything, as I discovered when the bug reports started flowing in :) Now the problem happens the other way round - in any month with less than 31 days, trying to set startDate to the 31st causes the month to increment. Setting the day, month and year separately was a legacy of the old millisecond code, so the real fix was to use the Date constructor as intended:

new Date((2000 + startDateYear), startDateMonth, startDateDay)