Working with Time (Part I)

MISSION: Given a month, day, and year, display the day of the week
SKILLS: Knowledge of the Gregorian Calendar, Modular Arithmetic

Greetings fellow coders, I apologize for my recent absence - I've been spending my days working on school projects and studying, so time to write up challenges hasn't been readily available. Today, however, I've decided to take a break from my business/laziness and offer up a nice little challenge.

I'll be upfront with you - this was a challenge I worked on to test my programming skills back when I first started programming. It's not very difficult, but it really gets you thinking. It's also nice to see how your computer does these things automatically.

So today we'll be working on accepting a date (a month, day, and year) and outputting what day of the week it was (Monday, Tuesday, etc.) on that particular day. For beginners, it may seem daunting - and you might think this is only solvable with some pretty gross code. But have faith in yourselves, my friends - the solution is short, elegant, and makes sense! Let's break it down.

So the general approach I've taken is a) finding out how many days it has been since January 1st, 1 AD (which was a Monday) and b) performing some modular arithmetic on that number to tell me what day of the week it is. That's really all it is - but before you can continue, let's make sure you have a good enough understand on how our calendar works exactly.

There are 12 months in our calendar (January, February -- wait, I think I'm going a bit too slow here. Let's refer to an olde English rhyme.

Thirty days hath September,
April, June, and November;
All the rest have thirty-one,
Save February, with twenty-eight days clear,
And twenty-nine each leap year.

Pretty straight-forward, huh? Well, except that last part about the leap year. To correct for the fact that the Earth does not revolve around the sun exactly once every 365 days, every four years we add 1 day to February. The problem is, we don't do this every year...

Instead, a leap year occurs once every four years, EXCEPT years divisible by 100, BUT INCLUDING, years divisible by 400.

So the year 2008 had a leap year, as did 2000 (2000 is divisible by 400), but the year 1900 did not. Figure out a way to logically include this in your program. Hint: Don't you dare go through each year manually! Now let's check out some input.

new-host:working-with-time jordan$ ./time.py
Enter a month (1-12): 1
Enter a day (1-31): 1
Enter a year (> 0): 1
January 1, 1 is a Monday
new-host:working-with-time jordan$ ./time.py
Enter a month (1-12): 7
Enter a day (1-31): 20
Enter a year (> 0): 1992
July 20, 1992 is a Monday
new-host:working-with-time jordan$ ./time.py
Enter a month (1-12): 12
Enter a day (1-31): 4
Enter a year (> 0): 2011
December 4, 2011 is a Sunday
new-host:working-with-time jordan$

Remember, the point here is to not use your language's date/time libraries. Do it from scratch! So best of luck to you all! And we'll be working with time again very soon - when I get some.

Best,
Jordan

7 thoughts on “Working with Time (Part I)

  1. #!/usr/bin/perl
    #2011.12.04
    use strict;
    use warnings;
    use DateTime;
    print DateTime->new(year=>$ARGV[0], month=>$ARGV[1], day=>$ARGV[2])->day_name."\n";

    Yea perl is for lazy people.

      • #!/usr/bin/perl
        #2011.12.04
        use strict;
        use warnings;
        
        my $o =
          {
            a =>
              {
                1  => 31,
                2  => 28,
                3  => 31,
                4  => 30,
                5  => 31,
                6  => 30,
                7  => 31,
                8  => 31,
                9  => 30,
                10 => 31,
                11 => 30,
                12 => 31
              },
            b => $ARGV[0],
            c => $ARGV[1],
            d => $ARGV[2],
            f => sub { $_[0] % 4 ? 0 : $_[0] % 100 ? 1 : $_[0] % 400 ? 0 : 1 },
            g => sub { my $o = 0; $o += $_ for @_; $o },
            h => sub {qw(Monday Tuesday Wednesday Thursday Friday Saturday Sunday)[$_[0]%7]}
          };
        
        print $o->{h}->($o->{g}->((map { 365 + $o->{f}->($_) } 1 .. $o->{b} - 1), (map { $o->{a}->{$_} } 1 .. $o->{c} - 1), $o->{d} - 1, $o->{c} > 2 ? $o->{f}->($o->{b}) : 0 ))."\n";
  2. How about some Python:

    dow = lambda y,m,d: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'][((y-1)*365 + (y-1)/4  - (y-1)/100 + (y-1)/400 + sum([0,31,28,31,30,31,30,31,31,30,31,30,31][:m]) + d-1 + (1 if m>2 and (y%4==0 and not y%100==0 or y%400==0) else 0)) % 7]
    
    print dow(2011,12,4)
    
  3. This is an interesting problem, complicated by the Gregorian calendar system and the “10 dropped days” when the switch was made from the Julian system to the Gregorian (see: https://en.wikipedia.org/wiki/Gregorian_calendar). When I compared my code’s answers for early dates using the cal command, I would get a different answer:

    cal jan 1

    gives the day to be Saturday not Monday.

    #!/usr/bin/python
    # usage dayofweek.py <month 1-12> <day of month> <year>
    import sys
    current_year = int(sys.argv[3])
    current_month = int(sys.argv[1])
    current_day = int(sys.argv[2])
    years = current_year - 1 
    
    # number of days through last complete year
    num_days = years * 365 + years / 4 - years / 100 + years / 400 
    
    months = [(0,'na'),(31,'January'),(28,'February'),(31,'March'),
              (30,'April'),(31,'May'),(30,'June'),(31,'July'),
              (31,'August'),(30,'September'),(31,'October'),
              (30,'November'),(31,'December')]
    
    days = ['Sunday','Monday','Tuesday','Wednesday','Thursday',
            'Friday','Saturday']
    
    # Add the basic number of days for current year
    num_days += current_day
    for i in range(1, current_month ):
        num_days += months[i][0]
    
    # Add day if it is a leap year
    if (current_month > 2 and (current_year % 4) == 0
        and  (current_year % 100 != 0 or current_year % 400 == 0)):
        num_days +=1 
    
    print "".join([months[current_month][1], " ",
                   str(current_day), ", ",
                   str(current_year), " is a ",
                   days[num_days % 7]])
    
  4. Pingback: Who came up with these dates? « Read Ink

  5. So… this is just awful looking, completely procedural and not exactly efficient… but… it works! Perfectly.

    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    int whatDay(int day, int month, int year){
        int final;
        int monthCode;
        int yearCode;
        bool isLeap;
    
        if (year%400 == 0) isLeap = true;
        else if (year%100 == 0) isLeap = false;
        else if (year%4 == 0) isLeap = true;
    
        if(month == 1 && isLeap) monthCode = 5;
        else if (month == 1 && !isLeap) monthCode = 6;
        else if (month == 2 && isLeap) monthCode = 1;
        else if (month == 2 && !isLeap) monthCode = 2;
        else if (month == 3) monthCode = 2;
        else if (month == 4) monthCode = 5;
        else if (month == 5) monthCode = 0;
        else if (month == 6) monthCode = 3;
        else if (month == 7) monthCode = 5;
        else if (month == 8 ) monthCode = 1;
        else if (month == 9) monthCode = 4;
        else if (month == 10) monthCode = 6;
        else if (month == 11) monthCode = 2;
        else if (month == 12) monthCode = 4;
    
        yearCode = ((((year - ((year/100)*100))/4)) + (year-((year/100))*100))%7;
    
        final = (day + monthCode + yearCode)%7;
    
        if (((year/100)%4) == 1)
            final += 5;
        else if (((year/100)%4) == 2)
            final += 3;
        else if (((year/100)%4) == 3)
            final += 1;
    
        return final;
    }
    
    int main(){
        int date, month, year;
    
        cout<< "Find the day of the week with any date (according to the Gregorian calendar)!"<<endl;
        cout<<"Enter the date!"<<endl;
        cin>>date;
        cout<<"Enter the month!"<<endl;
        cin>>month;
        cout<<"Enter the year! (YYYY)"<<endl;
        cin>>year;
    
        if(whatDay(date, month, year) == 0) cout<<"Sunday!";
        else if(whatDay(date, month, year) == 1) cout<<"Monday!";
        else if(whatDay(date, month, year) == 2) cout<<"Tuesday!";
        else if(whatDay(date, month, year) == 3) cout<<"Wednesday!";
        else if(whatDay(date, month, year) == 4) cout<<"Thursday!";
        else if(whatDay(date, month, year) == 5) cout<<"Friday!";
        else if(whatDay(date, month, year) == 6) cout<<"Saturday!";
    
        return 0;
    }
    

Leave a Reply