Dispersion Design

< Back

Calculating the Day of the Week

2012-04-19

In summary:

Given a date, the day of the week can be calculated:

var a = month < 3 ? 1 : 0;
var b = year - a;

var day_of_week = (date + Math.floor(31 * (month - 2 + 12 * a) / 12) +
	b + Math.floor(b / 4) - Math.floor(b / 100) +
	Math.floor(b / 400)) % 7;

Where month is 1 - January, 2 - February, etc and day_of_week is 0 - sunday, 1 - Monday, etc

Introduction

If you are given any date, it would seem that determining what day of the week that date falls on would be quite a difficult task. As it turns out, it is not really that difficult.

If you know the day of the week that one single reference date falls on, all you need to do is calculate how many days between that reference date and the date you wish to calculate. We often do this in our heads: determining that today must be Monday because we remember that yesterday was Sunday. If I told you that 7 days ago was a Tuesday, you would know that today is a Tuesday as well. If 14283 days ago was a Friday… OK, that is what we use computers for!

For our reference date, we will choose the 29th of February, 0000. We choose this date, rather than the 1st of January, because some of the math is easier.

Years

First, how many years have passed since the reference date? As first glance you might think that it is (year - 0000), but we actually need to consider whether the current date has reached 1 March to have rolled over a whole year. This is calculated as:

var b = year - (month < 3 ? 1 : 0);

Most years have 365 days. 364 divides evenly by 7, so for every non-leap year that has passed we increase the day of the week by one day. Since a leap year has 366 days, we increase the day of the week by two days for every leap year between the reference date and the date of interest. The code for this looks like:

day_of_week += b + Math.floor(b / 4) - Math.floor(b / 100) +
	Math.floor(b / 400);

If you don't understand why it is important to know how many 100 years and 400 years have passed, take a look at my blog post on how to determine leap years.

Months

Next we need to know how many complete months have passed since the reference month. If the month of interest is March, then no complete months have passed. If the month of interest is April, then one month has passed. This wraps around so that January means 10 complete months have passed.

var c = month - 3 + 12 * (month < 3 ? 1 : 0);

Once the number of complete months are known, the day of the week can be increased with the following equation:

day_of_week += Math.floor((31 * (c + 1)) / 12) - 2;

How did I get this equation? Well, as it turns out, there are a variety of equations that would work here. Even though each month has a different number of days, we can approximate the number of days with a best-fit straight line and then use the floor() function to give us the correct integer value. Confused? My post on calculating the number of days that have passed in a year explains this technique in more detail.

Days

Finally, the number of days in the current month are added:

day_of_week += date;

Then, since there are only 7 days in the week, we need to remove all the times that the days of the week have wrapped to a new week:

day_of_week = day_of_week % 7;

Putting it together

So, what value should the day of the week (day_of_week) start at? Well, the Gregorian calendar system did not exist on 29 Feb 0000, and there were a few days in 1752 that were skipped, but if we ignore those minor details then that day would have been a Tuesday (day_of_week = 2).

Combining all these calculations into one block of code results in:

var a = month < 3 ? 1 : 0;
var b = year - a;
var c = month - 3 + 12 * a;

var day_of_week = 2;
day_of_week += b + Math.floor(b / 4) - Math.floor(b / 100) +
	Math.floor(b / 400);
day_of_week += Math.floor((31 * (c + 1)) / 12) - 2;
day_of_week += date;
day_of_week = day_of_week % 7;

Simplifying this code gives the final solution:

var a = month < 3 ? 1 : 0;
var b = year - a;

var day_of_week = (date + Math.floor(31 * (month - 2 + 12 * a) / 12) +
	b + Math.floor(b / 4) - Math.floor(b / 100) +
	Math.floor(b / 400)) % 7;

Demo