Ground Rules

  1. We start where your program knows the value of m, d, and y (or month, day, and year), perhaps checking for non-numeric and non-zero data or invalid dates. The output will be an integer in the range 0-6 that can be used as a subscript in a days-of-the-week table or in a case lookup.
  2. The phrase later in the week can mean exactly that or wrap around to the next week. Two days later than Monday is Wednesday or two days after Friday is Sunday. Or, imagine a week as a pie chart divided into 7 sections, about 51.43 degrees each.
  3. All terms requiring division will either be done (depending on the programming or scripting language) with integer arithmetic or an appropriate "floor" or "truncate" function to remove any digits after the decimal point.

Description of Algorithm

This is based on Zeller's work.

Note that beginning with March, August, and January (only starts) the month lengths are 31-30-31-30-31. To take advantage of that, treat January and February as months 13 and 14 of the previous year. Transcribe "if month < 3, add 12 to month and subtract 1 from year" into your language. This puts leap year day at the end of the year and eliminates the problem of moving from February to March (more on that later).

There is an expression which, when modulus divided by 7, will give the subscript mentioned earlier. It doesn't matter what its value is, only that its value will change for the next day, next year, next month, or next leap year. Take June 3, 1993, a Thursday (Billie Jo McAlister day).

What needs to happen when the day is changed? The next day of the month will obviously be the next day of the week so the day of the month would be a term by itself. What about the year? Going from 1993 to 1994 is a non leap year of 365 days. When divided by 7, there is a remainder of 1 so the date of next year would also make the day of the week one day later (June 3, 1994 is Friday), so year would be in the expression. Leap years are covered later.

Except for February, all months contain at least 30 days which, when divided by seven gives a remainder of 2, so July 3, 1993 was a Saturday. In this case, 2 * month would be in the expression.

The tricky part is doing the 31 day months. In this case, we need an expression that will not change value after a 30 day month, but will increase by one after a 31 day month. It should be no surprise that 3/5 is multiplied by the month, but 3*(month + a)/5 allows the times the term increases to be changed. The value should increase in the 2nd month (after a 31 day month), 4th month (same reason), and 6th month (same as 1st month). August and January both follow 31 day months in the just prior cycle. Solve for a as an exercise.

Another approach is to look where the value would not change after the 30 day months, (3rd and 5th months).

Going from February to March is not a problem. The month number would change from 14 to 3 and it would be the next year.

There are several leap year rules to follow in the expression. Year/4 will change at the beginning of a leap year (March in our case). The century years not being leap can be done by subtracting year/100 in the expression, but the exception that years divisible by 400 are leap years can be fixed by adding year/400. If years divisible by 4000 are not to be leap years, subtract year/4000.

The resulting expression and code may look like this:

asum = d + 2*m + 3*(m+a)/5 + y + y/4 - y/100 + y/400 - y/4000 + b
dowIndex = asum % 7
weekDayName[dowIndex] will be displayed

If you have a weekDayName table that runs Sunday through Saturday (for example), experiment with the value of b if it shows the wrong day. Midpoint between two dates/times Also, add or subtract to/from a date/time.
Shows day-of-week from date. Does both Gregorian and Julian calendars.
Determine dates in your head. If you know today's date, you are all set.
Misc. programs