Dispersion Design

< Back

Algorithm for Determining the Number of Days in a Month

2012-04-12

In summary:

The number of days in a month can be calculated as:

var daysInMonth = (month === 2) ?
		(28 + isLeapYear) : 31 - (month - 1) % 7 % 2;

Where the month is represented as a number between 1 and 12 and isLeapYear is 1 if the year is a leap year.

Also, make sure you read my article on how to calculate whether a year is a leap year.

Introduction

Thirty days hath September,
April, June, and November;
All the rest have thirty-one…
http://en.wikipedia.org/wiki/Thirty_days_hath_September

Some people may have learned this rhyme in school as a way of remembering how many days there are in each month. Of course, you cannot teach rhymes to computers as easily as you can to children, so we face the problem of how to write a program to determine the number of days in a month.

The following table shows the month number (1-12), name of the month and number of days in that month:

Month Month Name Number of Days
1 January 31
2 February 28 (29 for leap years)
3 March 31
4 April 30
5 May 31
6 June 30
7 July 31
8 August 31
9 September 30
10 October 31
11 November 30
12 December 31

Solution #1

A first attempt at an algorithm, writing the code in JavaScript, might look something like this:

var daysInMonth;

if (month === 2) { // February
	if (isLeapYear) {
		daysInMonth = 29;
	} else {
		daysInMonth = 28;
	}
} else if (month === 4 || month === 6 ||
	month === 9 || month === 11) {
	daysInMonth = 30;
} else {
	daysInMonth = 31;
}

This works just fine, but we can improve upon this.

Solution #2

When trying to write cleaner code, you might be tempted to simply store the number of days in an array like the following:

var daysArray = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

daysInMonth = daysArray[month - 1];
if (month === 2 && isLeapYear) {
	daysInMonth = daysInMonth + 1;
}

This is pretty straightforward and can be very fast for calculating many results, provided the array of days (daysArray) is declared only once and reused:

var i;
var daysArray = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

for (i = 0; i < months.length; i = i + 1) {
	daysInMonth[i] = daysArray[month[i] - 1];
	if (month[i] === 2 && isLeapYear[i]) {
		daysInMonth[i] = daysInMonth[i] + 1;
	}
}

Solution #3

Further analysis reveals and interesting pattern that we can use to our advantage. First, since February is a special exception, we can temporarily pretend that there are 31 days in February. Now, when we write the number of days in each month we get the following:

month 1 2 3 4 5 6 7 8 9 10 11 12
Number of days 31 30 31 30 31 30 31 31 30 31 30 31

Rewriting the pattern in terms of letters A (31 days) and B (30 days) makes the pattern more obvious:

month 1 2 3 4 5 6 7 8 9 10 11 12
Pattern A B A B A B A A B A B A

The numbers alternate between 31 days and 30 days, then the pattern restarts in August (month 8). A seven digit repeating sequence can be created using the modulus (mod, or %) operator (i % 7). Performing a mod-2 operation on the seven digit repeating sequence then gives us the final pattern that we need ((i % 7) % 2):

ii % 7(i % 7) % 2
000
111
220
331
440
551
660
700
811
920
1031
1140

A few small adjustments are needed:

  1. Translate the pattern from i = (0, 1, 2, …, 11) to month = (1, 2, 3, …, 12)
  2. Return a result of 31 and 30 instead of 0 and 1
  3. Handle the special case of month == 2 (February)

And we get:

var daysInMonth;

if (month === 2) {
	daysInMonth = 28 + isLeapYear;
} else {
	daysInMonth = 31 - (month - 1) % 7 % 2;
}

This solution can also be written in a different way by using the ternary conditional operator (i.e. 'condition' ? 'then' : 'else'):

var daysInMonth = 31 - ((month === 2) ?
	(3 - isLeapYear) : ((month - 1) % 7 % 2));

And we are finished! An elegant, one-line solution to the problem. Of course it is also necessary to determine whether the current year is a leap year. The algorithm for that is presented in my leap year article.

Other Programming Languages

C, C++ and Java

Very little modification is needed to express the leap year calculation in C, C++ or Java:

int daysInMonth = 31 - ((month == 2) ?
	(3 - isLeapYear) : ((month - 1) % 7 % 2));

Perl and PHP

And translating the leap year calculation into PHP or Perl:

$daysInMonth = 31 - (($month == 2) ?
	(3 - $isLeapYear) : (($month - 1) % 7 % 2));

Demo