## Any Day of the Week Using the Doomsday Rule

An ingenious yet simple way to calculate the day of the week for any date was invented by
John Conway called the **Doomsday rule**. I highly recommend reading the
article by S.W. Graham
which fully describes the algorithm. Basically by knowing which day of the week February 28 or 29 (leap year) falls
on during a given century and which day of the week corresponds to that day for all the other months one can
determine any day of the week. The following table summarizes which integers represent weekdays and what day represents the doomsday
for the month and century.

Since the *Gregorian Calendar* repeats every 400 years one really only needs to remember four centuries. For example
which day of week was November 5^{th}, 1955? (more importantly which movie uses that date?).

The year part is **55**
The day is **5**
Doomsday Century for 1900 is **3**
Doomsday Month for November is **7**
Every leap year the doomsday is increased by one.
We add the Doomsday Century + Year Part + Floor(Year Part ÷ 4) % 7
For this example: (3 + 55 + *floor*(55 ÷ 4)) % 7 = **1**
Since the doomsday for November is after the day we must figure out what the offset is. We know the doomsday
is on the 7^{th} and the 5^{th} is 2 days prior or the same day as a week later which would be the
12^{th} or 5 days after the 7^{th}. Therefore we add 5 to the doomsday which is 12. The remainder
of 12 ÷ 7 is 5 which is the correct day.
Finally we need to account for leap year so 5 + 1 = 6 or Saturday.
The `COleDateTime`

class has date limits from **Jan 1, 100** to **Dec 31, 9999** and
the `CTime`

class has date limits from **Jan 1, 1970** to **Jan 18, 2038**. The `DoomsdayDate`

class can be used to find the day of the week during any range including B.C. dates.

## DoomsdayDate

class DoomsdayDate
{
DoomsdayDate(bool JulianBeforeGregorian = true);
bool AD() { return ad_; }
bool BC() { return !ad_; }
bool Set(int month, int day, int year, bool ad=true);
bool SetFirst(int weekday, int month, int year);
bool SetSecond(int weekday, int month, int year);
bool SetThird(int weekday, int month, int year);
bool SetFourth(int weekday, int month, int year);
const char* WeekdayStr(int weekDay);
int GetDay() { return day_; }
int GetMonth() { return month_; }
int GetYear() { return year_; }
int Weekday();
void Print();
}

## DoomsdayDate Weekday Function

The core of the doomsday algorithm is the `Weekday`

function.

int Weekday()
{
int r = -1;
int x = 0, y = 0;
int ddcentury = -1;
int ddmonth = DoomsdayMonth(month_);
if( gregorian_ )
{
int century = year_ - (year_ % 100);
ddcentury = DoomsdayCentury(century);
if( ddcentury < 0 ) return -1;
if( ddmonth < 0 ) return -1;
if( ddmonth > day_ )
{
weekday_ = (7 - ((ddmonth-day_) % 7 ) + ddmonth);
}
else
{
weekday_ = day_;
}
x = (weekday_ - ddmonth);
x %= 7;
y = ddcentury + (year_-century) + (floor((year_-century)/4));
y %= 7;
r = (x+y)%7;
}
else if( !ad_ )
{
int dd = -1;
if( year_ > 699 )
{
dd = (year_ - (year_ % 700) + 701) - year_;
}
else
{
dd = (year_ - (year_ % 28) + 29) - year_;
}
if( dd > 0 )
{
ddcentury = (((dd - (dd % 100)) / 100) * 6)%7;
x = ((dd%100)%7) + (int)floor((dd%100)/4)%7;
if( ddmonth > day_ )
y = ddmonth + day_;
else
y = day_ - ddmonth;
y %= 7;
x = ddcentury + x;
x %= 7;
r = (x+y)%7;
}
}
else
{
ddcentury = (((year_ - (year_ % 100)) / 100) * 6)%7;
x = ((year_%100)%7) + (int)floor((year_%100)/4)%7;
if( ddmonth > day_ )
y = ddmonth + day_;
else
y = day_ - ddmonth;
y %= 7;
x = ddcentury + x;
x %= 7;
r = (x+y)%7;
}
weekday_ = r;
return weekday_;
}

## DoomsdayDate Usage

The default constructor takes a boolean which indicates if the Julian calendar should be used prior
to October 15^{th}, 1582 which defaults to `true`

. Since October 5-14, 1582 were omitted from the Gregorian
calendar they are not valid dates. If false is passed in all dates are synchronized with the Gregorian calendar.

The sample project takes the following arguments:

**
MM
DD
YYYY
[BC]
**

where BC is optional to indicate if the date is B.C. It will also output the day of the week that `COleDateTime`

will
calculate for comparison purposes. Some interesting results of the sample program are below:

DoomsdayDate | COleDateTime |
---|

Saturday 10/14/1066 | Sunday 10/14/1066 |

Sunday 12/7/1941 | Sunday 12/7/1941 |

Sunday 10/23/4004 B.C. | Can't handle B.C. dates |

Friday 12/31/9999 | Friday 12/31/9999 |

Saturday 1/1/10000 | ¦¦¦¦¦¦¦¦¦¦¦¦¦¦ 1/1/10000 |

## Legal U.S. Holidays

The following code uses the `DoomsdayDate`

class to calculate which date all legal U.S.
holidays occur on. It is contained in the LegalHoliday.h file.

namespace
{
DoomsdayDate NewYears(int year)
{
return DoomsdayDate(Month::JAN, 1, year);
}
DoomsdayDate MartinLutherKingJr(int year)
{
DoomsdayDate dd;
dd.SetThird(Weekday::MONDAY, Month::JAN, year);
return dd;
}
DoomsdayDate WashingtonsBirthday(int year)
{
DoomsdayDate dd;
dd.SetThird(Weekday::MONDAY, Month::FEB, year);
return dd;
}
DoomsdayDate MemorialDay(int year)
{
DoomsdayDate dd;
dd.SetFourth(Weekday::MONDAY, Month::MAY, year);
return dd;
}
DoomsdayDate IndependenceDay(int year)
{
return DoomsdayDate(Month::JUL, 4, year);
}
DoomsdayDate LaborDay(int year)
{
DoomsdayDate dd;
dd.SetFirst(Weekday::MONDAY, Month::SEP, year);
return dd;
}
DoomsdayDate ColumbusDay(int year)
{
DoomsdayDate dd;
dd.SetSecond(Weekday::MONDAY, Month::OCT, year);
return dd;
}
DoomsdayDate VeteransDay(int year)
{
return DoomsdayDate(Month::NOV, 11, year);
}
DoomsdayDate ThanksgivingDay(int year)
{
DoomsdayDate dd;
dd.SetFourth(Weekday::THURSDAY, Month::NOV, year);
return dd;
}
DoomsdayDate ChristmasDay(int year)
{
return DoomsdayDate(Month::DEC, 25, year);
}
};

For this year the following outputs were generated:

**Holidays 2002**
=======================================
New Years is on a Tuesday 1/1/2002
Martin Luther King Jr. is on Monday 1/21/2002
Washington's Birthday is on Monday 2/18/2002
Memorial Day is on Monday 5/27/2002
Independence Day is on a Thursday 7/4/2002
Labor Day is on Monday 9/2/2002
Columbus Day is on Monday 10/14/2002
Veterans Day is on a Monday 11/11/2002
Thanksgiving Day is on a Thursday 11/28/2002
Christmas Day is on a Wednesday 12/25/2002

## *Note on Unnamed Namespaces

The **C++ standard** states the following concerning anonymous or unnamed namespaces and their purpose.

*Section 7.3.1.1 paragraph 2:*

"The use of the static keyword is deprecated when declaring objects in a namespace scope; the unnamed-namespace provides a superior alternative. Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit."