Closed Bug 361214 Opened 18 years ago Closed 18 years ago

Date.setMonth method does not work logically

Categories

(Core :: JavaScript Engine, defect)

x86
Linux
defect
Not set
minor

Tracking

()

VERIFIED INVALID

People

(Reporter: trevor_garrick, Unassigned)

Details

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0

When using the Date.setMonth() method, the month incrementing isn't logical (though this may be a difference of opinion how the method should work).  When incrementing from a 31 day month into a 30 or 28(29) day month, the month will increment into the next month plus a couple of days (i.e. Date.setMonth(1) when the date object is Jan. 31, 2007 will produce March 3, 2007)

Reproducible: Always

Steps to Reproduce:
1.var foo = new Date(2007, 0, 31);
2.foo.setMonth(foo.getMonth() + 1);
3.document.write(foo.toString());

Actual Results:  
Sat Mar 03 2007 00:00:00 GMT-0700 (MST) 

Expected Results:  
Logically, the setMonth() should have returned Feb. 28, 2007

I did a work around using the following code:

var MonthDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var oMat = new Date(2007, 0, 31);
var PayDate = oMat.getDate();

for (var x = 0; x < 60; x++) {
	if (oMat.getFullYear() % 4 == 0) {
		MonthDays[1] = 29;
	}
	else {
		MonthDays[1] = 28;
	}

	if (oMat.getMonth() + 1 != 12) {
		if (MonthDays[oMat.getMonth()+1] < PayDate) {
			var currMonth = MonthDays[oMat.getMonth() + 1];
			oMat.setMonth(oMat.getMonth() + 1, currMonth);
		}
		else {
			oMat.setMonth(oMat.getMonth() + 1, PayDate);
		}
	}
	else {
		oMat.setMonth(oMat.getMonth() + 1, PayDate);
	}
}

Obviously there are still some problems with this:

1. Doesn't take into account century non-leap years (2100, 2200, etc.)
2. It is inefficient to set the MonthDays[1] every iteration.
I think it works correctly but you are trying to do something which it's not designed for... You're setting 31 Feb 2007 which is equivalent to 3 March 2007.

This page (scroll down to the javascript section):
http://classicasp.aspfaq.com/date-time-routines-manipulation/how-do-i-calculate-dates-such-as-the-first-day-of-the-month.html
has details of a number of useful date functions, notably:

var ldtm = new Date(thisYear, thisMonth + 1, 0); 
rw("Last day of this month:", ldtm.toDateString());

which should probably form the basis of what you are attempting.
I would set this INVALID but I couldn't actually find an authoritative source for 31 Feb = 3 Mar so I'll leave it to someone more qualified.
IE6, Firefox, Opera9 all agree on this. Invalid.
Status: UNCONFIRMED → RESOLVED
Closed: 18 years ago
Resolution: --- → INVALID
Verified by evaluating |var d = new Date(2006, 0, 31); d.setMonth(1);| against the spec.  Specifically, note that step 7 in MakeDay returns the beginning of February, and step 8 determines the day which is 31 days after the first day in February (i.e., date wraparound occurs).

While looking at this, however, I discovered, that if the argument to setMonth is out of range (i.e., not 0-11), the date object isn't invalidated; filed as bug 361325.
Status: RESOLVED → VERIFIED
You need to log in before you can comment on or make changes to this bug.