If the month isn't February, get the number from the array. Otherwise, check if the year is leap to return 29, or return 28. Is there a problem with that?
I'm mostly agreeing w/ Moayad. I'd use a table lookup, with an if check on February and the year.
pseudocode:
Last_Day = Last_Day_Of_Month[Month];
Last_Day += (Month == February && Leap_Year(Year)) ? 1 : 0;
Note that Leap_Year() can't be implemented simply as (Year % 4 == 0)
, because the rules for leap years are way more complex than that. Here's an algorithm cribbed from Wikipedia
bool Leap_Year (int year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
function caldays(m,y)
{
if(m==01||m==03||m==05||m==07||m==08||m==10||m==12)
{
var dmax = 31;
return dmax;
}
else if (m==04||m==06||m==09||m==11)
{
var dmax = 30;
return dmax;
}
else
{
if((y%400==0) || (y%400==0 && y%100!=0))
{
dmax = 29;
return dmax;
}
else
{
dmax = 28;
}
return dmax;
}
}
I agree with Moayad and TED. Stick with the lookup table unless the month is February. If you need an algorithm for checking leap years, wikipedia has two:
if year modulo 400 is 0 then leap
else if year modulo 100 is 0 then no_leap
else if year modulo 4 is 0 then leap
else no_leap
A more direct algorithm (terms may be grouped either way):
function isLeapYear (year):
if ((year modulo 4 is 0) and (year modulo 100 is not 0)) or (year modulo 400 is 0)
then true
else false
I've been doing this using the Date object (assuming it's compiled, and hence blindingly fast compared to scripting).
The trick is that if you enter a too high number for the date part, the Date object wraps over into the next month. So:
var year = 2009;
var month = 1;
var date = 29;
var presumedDate = new Date(year, month, date);
if (presumedDate.getDate() != date)
WScript.Echo("Invalid date");
else
WScript.Echo("Valid date");
This will echo "Invalid date" because presumedDate is actually March 1st.
This leaves all the trouble of leap years etc to the Date object, where I don't have to worry about it.
Neat trick, eh? Dirty, but that's scripting for you...
function daysInMonth(m, y) { // m is 0 indexed: 0-11
switch (m) {
case 1 :
return (y % 4 == 0 && y % 100) || y % 400 == 0 ? 29 : 28;
case 8 : case 3 : case 5 : case 10 :
return 30;
default :
return 31
}
}
function isValid(d, m, y) {
return m >= 0 && m < 12 && d > 0 && d <= daysInMonth(m, y);
}
This will not perform as well as the accepted answer. I threw this in here because I think it is the simplest code. Most people would not need to optimize this function.
function validateDaysInMonth(year, month, day)
{
if (day < 1 || day > 31 || (new Date(year, month, day)).getMonth() != month)
throw new Error("Frack!");
}
It takes advantage of the fact that the javascript Date constructor will perform date arithmetic on dates that are out of range, e.g., if you do:
var year = 2001; //not a leap year!
var month = 1 //February
var day = 29; //not a valid date for this year
new Date(year, month, day);
the object will return Mar 1st, 2001 as the date.
Assuming the JS Date object standard where months are numbered from 0, and you have your daysInMonth array:
var days = daysInMonth[month] + ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0)));
will give you the number of days in the month, with 28 increased to 29 iff the month is February and the year is a leap year.
all this logic is already built in to the javascript engine... Why recode it ? Unless you are doing this just as an exercise, you can use the javascript Date object:
Like this:
function daysInMonth(aDate) {
return new Date(aDate.getYear(), aDate.getMonth()+1, 0).getDate();
}
You can use DateTime to solve this:
new DateTime('20090901')->format('t'); // gives the days of the month