Assigned:Friday, February 14
Due: Sunday, February 23, 2020 by 11:55pm
A perpetual calendar is a calendar designed to be valid for many years, usually designed to look up the day of the week for a given date in the future. In this project, you will design a perpetual calendar by writing a number of functions.
Follow the steps below to implement your project. There are eleven steps, but they are all relatively short, so it looks a lot more involved than it actually is.
When first thinking about a program, try to envision it as a set of components that all fit together like a puzzle, where each component handles a separate, distinct task. Consider making separate tasks into separate functions. Now this idea can be taken to the extreme, which is not helpful, as using too many functions, especially if these functions all need access to the same variables, ends up being very messy because you have to write functions that take, for instance, ten arguments. Try to find a balance between too many functions and too few.
Step 2: Review the guidelines for coding style and comments. Now that we are adding functions, every function you write, except main(), must have a comment before it explaining what the function does, what the parameters are, and what the return value is.
Step 3: Create a new, blank Python program. Type the standard comment header at the top.
Step 4 (Determining if a year is a leap year): Write a function called is_leap that takes a parameter called year, which will be an integer. Your function should return True if the year is a leap year, and False if it is not.
The definition line of this function should look like this def is_leap(year):
Hints:
>>> is_leap(2000) True >>> is_leap(1900) False >>> is_leap(2004) True >>> is_leap(2005) False |
When your function passes all of these tests, move on to Step 5.
Step 5 (Determining the day of the year): In the next two steps, we will write a function to determine the day of the year that a date falls on. For instance, January 1 is (obviously) the first day of the year. December 31 is the 365th day of the year, but the 366th day in a leap year. If you're curious, here's a website where you can see the days of the year for any year.
The first step in creating this function is to create a helper function (a helper function is a function designed to be called from another function, in order to help it do its job). This helper function will be called magic_month and it is designed to return the number of days that have gone by in a year on the first of any month (assuming it's not a leap year). For instance, on January 1, zero days have gone by in the year so far. On February 1, 31 days have gone by (because January has 31 days). On March 1, 59 days have gone by (the 31 days of January, plus the 28 days of February, assuming it's not a leap year).
Define a function called magic_month that takes a parameter called month, that will be the integer representing a month (1=January, 2=February, and so on). This function should return the number of days gone by since the beginning of the year. Here's a table of what to return:
January (Month #1): 0 February (Month #2): 31 March (Month #3): 59 April (Month #4): 90 May (Month #5): 120 June (Month #6): 151 July (Month #7): 181 August (Month #8): 212 September (Month #9): 243 October (Month #10): 273 November (Month #11): 304 December (Month #12): 334
The definition line of this function should look like this def magic_month(month):
Hint: No need to be clever here. Just use an if-elif-else statement with twelve branches.
Step 5A: Test your magic_month function. Here are some examples:
>>> magic_month(1) 0 >>> magic_month(2) 31 >>> magic_month(7) 181 |
Step 6 (actually writing the day-of-year function): Write a function called day_of_year that takes three integer parameters: a month (1-12), a day (1-31), and a year (any year is possible). This function should return the day of year (1-366) that this date occurs on.
Here's how you do it. You need to two pieces of information: first, figure out whether the year is a leap year or not (hint---call your is_leap function on the year and capture the return value). Next, get the appropriate magic_month value for the month (hint---call your magic_month function on the month and capture the return value). The formula for finding the day of the year is quite simple:
The day of the year is the magic_month number plus the day of the month. If this year is a leap year and the month is March or later, add one to this result.
The definition line of this function should look like this def day_of_year(month, day, year):
Example: Suppose we call day_of_year(7, 29, 2019) to calculate the day of the year for July 29, 2019. 2019 is not a leap year, and the magic_month number for July (month #7) is 181. So the day of the year here is 181 + 29, which is 210.
Example 2: Suppose we call day_of_year(4, 11, 2016) to calculate the day of the year for April 11, 2016. 2016 is a leap year, and the magic_month number for April (month #4) is 90. So the day of the year here is 90 + 11 + 1, which is 102.
Step 6A: Test your day_of_year function. Here are some examples:
>>> day_of_year(7, 29, 2019) 210 >>> day_of_year(4, 11, 2016) 102 >>> day_of_year(12, 31, 2100) 365 |
Step 7: Over the next three steps you will write three more functions that will help you compute the day of the week for any given day in history. In order to do this, we will associate a number with every day of the week. Here's the pattern:
Sunday: 0 Monday: 1 Tuesday: 2 Wednesday: 3 Thursday: 4 Friday: 5 Saturday: 6The first function we will write, called new_years_day, will calculate the day of the week number (from the table above) for any January 1 in history. Here's how it works. The steps are:
Write this function called new_years_day, which takes an integer parameter called year, and returns an integer interpreted as a day of the week.
The definition line should be def new_years_day(year):
Step 7A: Test your new_years_day function. Here are some examples:
>>> new_years_day(2019) 2 >>> new_years_day(2020) 3 >>> new_years_day(1900) 1 >>> new_years_day(2021) 5 |
Step 8: You will now write a function called day_of_week. This function takes three parameters: the month (1-12), the day of the month (1-31), and the year. This function will finally compute the day of the week for any day of any year! Here's how it works. All you have to do is call your day_of_year function, passing in the month, day, and year parameters; and your new_years_day function, passing in the year parameter. If you add those values together, subtract one, divide the result by 7, and take the remainder, you will have your day of the week (as an integer!). Return this integer value.
Here's an example. Let's find the day of the week for July 29, 2019. We already know that day_of_year(7, 29, 2019) returns 210, and new_years_day(2019) returns 2. If we add these together and subtract 1, we get 210 + 2 - 1 = 211. 211 % 7 is 1, which means July 29, 2019 falls on a Monday (check it on a calendar if you want!).
Write this function in Python now. The definition line is def day_of_week(month, day, year):
Step 8A: Test your day_of_week function. Here are some examples:
>>> day_of_week(7, 29, 2019) 1 >>> day_of_week(12, 25, 2020) 5 >>> day_of_week(7, 4, 1900) 3 >>> day_of_week(2, 14, 2000) 1 |
Step 9: You're almost done. You're going to write one more function, called day_of_week_str, that does the same operation as day_of_week, except the answer is returned as a string (like "Sunday", "Monday", etc). This function takes three parameters: the month (1-12), the day of the month (1-31), and the year. Here's how it works. Simply call day_of_week, passing in the same three parameters you are given here.
Hint: After capturing the return value from day_of_week, use a 7-branching if-elif-else statement to determine the appropriate day of the week string and return it.
The definition line is def day_of_week_str(month, day, year):
Step 9A: Test your day_of_week_str function. Here are some examples:
>>> day_of_week_str(7, 29, 2019) 'Monday' >>> day_of_week_str(12, 25, 2020) 'Friday' >>> day_of_week_str(10, 31, 2056) 'Tuesday' |
Once you have written these functions, tested them, and they all work, you can move on to Step 10, which is writing the main function.
Pick a date, any date (such as your birthday!) What is the month? (1-12)? 7 What is the day? 29 What is the year? 1982 This is day number 210 of the year. This date falls on a Thursday. In 2020, this date falls on a Wednesday. In 1982, New Year's Day falls on a Friday. Would you like to pick another date? (y for yes): y Pick a date, any date (such as your birthday!) What is the month? (1-12)? 11 What is the day? 21 What is the year? 1981 This is day number 325 of the year. This date falls on a Saturday. In 2020, this date falls on a Saturday. In 1981, New Year's Day falls on a Thursday. Would you like to pick another date? (y for yes): y Pick a date, any date (such as your birthday!) What is the month? (1-12)? 2 What is the day? 14 What is the year? 2019 This is day number 45 of the year. This date falls on a Thursday. In 2020, this date falls on a Friday. In 2019, New Year's Day falls on a Tuesday. Would you like to pick another date? (y for yes): n
>>> find_thanksgiving(2019) 28 >>> find_thanksgiving(2020) 26 >>> find_thanksgiving(2021) 25 >>> find_thanksgiving(2000) 23 |
After writing this function, add more code to your main() that computes and prints out the day that Thanksgiving falls on in the year supplied by the user at the beginning of the program.
Your program will be graded on correctness, as well as on coding style, which refers to choices you make when writing your code, such as good use of variable names, appropriate indentation,
and comments (this is not an exhaustive list). See the syllabus for further grading details.
You will receive one bonus point for every complete day your program is turned in early, up to a maximum of five points. For instance, if your program is due on September 20 at 11:59pm, if you turn in your code on Moodle any time on September 19 from 12:00am through 11:59pm, you will receive one extra point on your project. Programs submitted on September 18 from 12:00am through 11:59pm will receive two points. This pattern continues for up to five points.