Click here to Skip to main content
Click here to Skip to main content

Any Day of the Week Using the Doomsday Rule

, 27 Jun 2002
Rate this:
Please Sign up or sign in to vote.
C++ implementation of the Doomsday Rule to determine the weekday.

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 5th, 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 7th and the 5th is 2 days prior or the same day as a week later which would be the 12th or 5 days after the 7th. 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
    {
    
    	//-----------------------------------------------------
    	// JulianBeforeGregorian refers to the weird dates
    	// between October 5-14, 1582 which were deleted from
    	// the Gregorian calendar.  Technically the days never
    	// existed.  The default is false which sets the date
    	// as invalid.
    	//-----------------------------------------------------
    	DoomsdayDate(bool JulianBeforeGregorian = true);
    
    	bool AD() { return ad_; }
    	bool BC() { return !ad_; }
    
    	// pass in ad = false for B.C. dates
    	//--------------------------------------------------
    	bool Set(int month, int day, int year, bool ad=true);
    
    	// Find the first, second, third, or fourth
    	// weekday in the specified month and year.
    	// Only A.D. dates are supported.
    	//----------------------------------------------
    	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);
    
    	// returns day of month
    	//---------------------------
    	int GetDay() { return day_; }
    
    	// returns int month
    	// 1 = January
    	// 2 = February
    	// ...
    	//-------------------------------
    	int GetMonth() { return month_; }
    
    	// returns int year
    	//-----------------------------
    	int GetYear() { return year_; }
    
    	// 0 == Sunday
    	// 1 == Monday
    	// 2 == Tuesday
    	// 3 == Wednesday
    	// 4 == Thursday
    	// 5 == Friday
    	// 6 == Saturday
    	//------------------
    	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_ ) // Gregorian Calendar
    	{
    		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_ ) // B.C -> AD Julian
    	{
    		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 // Julian Calendar
    	{
    		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 15th, 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 // *see note below
    {
    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."

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    Share

    About the Author

    Paul J. Weiss
    Web Developer
    United States United States
    No Biography provided

    Comments and Discussions

     
    GeneralDOW Algorithm using number series for days in month PinsussAnonymous2-Sep-04 14:31 
    GeneralMemorial day Pinmemberc_barnes30-Jun-04 11:41 
    GeneralRe: Memorial day Pinmembertupacs0117-Jul-05 10:05 
    GeneralTwo day sliding window PinsussKen Roszkowski30-Apr-03 13:40 
    QuestionWhat @ OS which uses time_t Pinsussanand paranjpe7-Apr-03 2:40 
    GeneralNovember 5, 1955 PinmemberMike Stevenson28-Jun-02 8:12 
    General1582 Pinmemberbenjymous28-Jun-02 0:53 
    GeneralRe: 1582 PinmemberPaul J. Weiss28-Jun-02 6:53 
    GeneralRe: 1582 PinmemberAnonymous29-Jun-02 11:35 
    GeneralRe: 1582 PinmemberGreg Russell1-Jul-02 4:08 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Terms of Use | Mobile
    Web01 | 2.8.1411023.1 | Last Updated 28 Jun 2002
    Article Copyright 2002 by Paul J. Weiss
    Everything else Copyright © CodeProject, 1999-2014
    Layout: fixed | fluid