• Advertisement
Sign in to follow this  

Need a fresh pair of eyes (getting day of the week)

This topic is 4650 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I used this inefficient algorithm to calculate the day of the week, based on the day of the month, what month it is, and what year it is. It seems to work until somewhere in between 1700 and 1800 for the year, and then it starts diverging from the output of 'cal' on my linux comp. Here is the algorithm, and required extra stuff. BTW, 1st of January, 1AD was a Saturday. A description of exactly how it works will follow.
enum
{
    JANUARY = 1,
    FEBRUARY = 2,
    MARCH = 3,
    APRIL = 4,
    MAY = 5,
    JUNE = 6,
    JULY = 7,
    AUGUST = 8,
    SEPTEMBER = 9,
    OCTOBER = 10,
    NOVEMBER = 11,
    DECEMBER = 12
};

enum
{
    MONDAY = 1,
    TUESDAY = 2,
    WEDNESDAY = 3,
    THURSDAY = 4,
    FRIDAY = 5,
    SATURDAY = 6,
    SUNDAY = 7
};



/*************************************************/
/* HERE IS THE PROBLEM :(                        */
/*************************************************/

unsigned int DayOfWeek( unsigned int day_of_month, unsigned int month_of_year, long year)
{
    unsigned long days = 0;
    /*****************************/
    /* In 1AD, the first of      */
    /* january was saturday.     */
    /* The date advances forward */
    /* by 1 per year, 2 on a     */
    /* leapyear.                 */
    /*****************************/
    if (DayOfYear(day_of_month, month_of_year, year) == 0 )
        return 0;
    if ( year < 1 )
    {
        for ( long i = 1 ; i > year; --i )
        {
            days += DaysInYear(i);
        }
        days += DayOfYear(day_of_month, month_of_year, year);
    }
    else
    {
        for ( long i = 1; i < year; ++i )
        {
            days += DaysInYear(i);
        }
        days += DayOfYear(day_of_month, month_of_year, year);
    }
    return ((days+4)%7+1);
}



Basically, it starts at 1 AD, and adds up the number of days in each year through the year before the year requested; then, it adds the number of days that have passed through the date requested. In the end, it takes the modulo 7, adds what it needs to to make it the correct date, since we start enumerating dates from Monday, and returns the value. It should work, shouldn't it? Thanks. I have more code if you need it

Share this post


Link to post
Share on other sites
Advertisement
The problem may be in your DaysInYear method.. Here's a routine I wrote a while back, using the following algorithm:


W=(C+Y+L+M+D)%7

Where:
  • W is the day of the week (0=Sunday, through 6=Saturday)
  • C is a code for the century from this table (for the Gregorian calendar only):
    1400s, 1800s, 2200s = 2
    1500s, 1900s, 2300s = 0
    1600s, 2000s, 2400s = 5
    1700s, 2100s, 2500s = 4
  • Y is the last two digits of the year.
  • L is the number of leap days since the beginning of the century.
    1. Divide the year (two digits) by 4 and throw away the fraction.
    2. Notice that 1900 and 1800 were not leap years, and 2000 was. Only century years divisible by 400 are leap years. So, add 1 for those centuries divisible by 4 (as we haven't counted the leap day for year 00 yet).
    3. Also, don't count a leap day if it happens after the date that you are calculating. In other words subtract one, if you are calculating a date of January or February of a leap year.

  • M is the code for the month:
    • Jan = 0
    • Feb = 3
    • Mar = 3
    • Apr = 6
    • May = 1
    • June = 4
    • July = 6
    • Aug = 2
    • Sep = 5
    • Oct = 0
    • Nov = 3
    • Dec = 5

  • D is the date.


*** source omitted.. contact poster if you need it ***

EDIT: Note.. this only works for the Gregoran calendar.. I tested it with every day between 1752 and 2099, and compared it with the Windows methods, and it matched up. I could hae just used the windows methods, but this function was 24% faster, and I needed it to be efficient.

Not sure what it'll do pre-1752.

[Edited by - pragma Fury on June 2, 2005 12:02:31 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Is this a personal exercise?

If not, http://www.opengroup.org/onlinepubs/007908799/xsh/getdate.html

Share this post


Link to post
Share on other sites
Be careful, too. If you're using the Gregorian calendar (which it looks like you are), Pope Gregory XIII changed the calendar in 1582 and shortened October by 10 days. Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).

So your calculation of the 1rst of January 1 AD may not be accurate. Just a heads up. See here for more info.

Share this post


Link to post
Share on other sites
If you want this to work on with all the various non-US calendars out there and if it's a Windows app you can call GetLocalTime. The resulting SYSTEMTIME structure has the day of the week in it. You can then use GetDateFormat to format it properly in a locale-aware way.

Share this post


Link to post
Share on other sites
Its a personal exercise, and real men ALWAYS re-invent the wheel :). Thats the whole point of libraries, right? To only use your own? </sarcasm>

I think I'll try out the algorithm on here - I'll bet its the day-shortening thing (does the 'cal' thing take care of that? Probably). Thanks to all who posted, though.

Share this post


Link to post
Share on other sites
Actually, I decided to just modify mine. It must have been the Pope Gregory thing, because 1583 is the first date where my algorithm fails. I'll let you know :). Thanks again!

Share this post


Link to post
Share on other sites
HA! I was vindicated. I cannot find a calendar that does all dates, and realizes that 4AD was NOT a leap-year. But mine does. Fwahaha! Day-of-week == DONE!

Share this post


Link to post
Share on other sites
Aww, I guess I'm too late to point it out... but I'll rub it in ;)

Quote:
It seems to work until somewhere in between 1700 and 1800 for the year, and then it starts diverging from the output of 'cal' on my linux comp.


Quote:
EDIT: Note.. this only works for the Gregoran calendar.. I tested it with every day between 1752 and 2099, and compared it with the Windows methods, and it matched up. I could hae just used the windows methods, but this function was 24% faster, and I needed it to be efficient.

Not sure what it'll do pre-1752.


So yeah, there you go.

Anyway, you might be interested in what wiki has to say about it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement