Assignment 3: Weekday Calculator (30 Points)

Chris Tralie

Due Monday 2/17/2020

Overview / Logistics

The purpose of this assignment is to get you practice with if statements, modular arithmetic, methods and testing with a fun application which will seem like magic once it works.

Click here to download the skeleton code for this assignment. You will be editing src/hw3_weekdaycalculator/HW3_WeekdayCalculator.java and test/hw3_weekdaycalculator/HW3_WeekdayCalculatorTest.java.

What to submit: When you are finished, you should submit these two files to Canvas. Please also submit answers to the following as a comment on Canvas:

  • Did you work with a buddy on this assignment? If so, who?
  • Are you using up any grace points to buy lateness days? If so, how many?
  • Approximately how many hours it took you to finish this assignment (I will not judge you for this at all...I am simply using it to gauge if the assignments are too easy or hard)
  • Your overall impression of the assignment. Did you love it, hate it, or were you neutral? One word answers are fine, but if you have any suggestions for the future let me know.
  • Any other concerns that you have. For instance, if you have a bug that you were unable to solve but you made progress, write that here. The more you articulate the problem the more partial credit you will receive (fine to leave this blank)

The Problem

In lab 1, we saw that the orbit of the earth around the sun is slightly longer than 365 days (actually, more specifically, the tropical year is just under 365.25 days), so we wrote a program in lab 2 to compute years that are used as leap years in to keep our calendar days in the Gregorian Calendar on track with the summer solstice.

Now that we understand the calendar, we are ready to create a program that computes the weekday that any date falls on. The date may be any day in the past, present or future. To accomplish this, we will implement an algorithm invented by mathematician John Conway called the Doomsday Algorithm. This algorithm relies on the fact that there are a set of days every year (e.g. April 4th and June 6th) which always share the same weekday. These days are referred to as doomsdays. The weekday in question changes from year to year, though, so the challenge becomes to compute that day for a particular year, and then to find the nearest doomsday as a reference. We will refer to this day of the week as "the doomsday" for a particular year, and we will refer to one of the doomsdays as "a doomsday" (e.g. 4/4 and 6/6). For instance, in 2020, the doomsday is Saturday, so June 6 (a doomsday), 2020 is on a Saturday (we will discuss how to compute this day for any year momentarily). Therefore, if we want to know the date of June 4, 2020, we would count back by 2 to a Thursday.

Let's now look at the steps of the Doomsday Algorithm in more detail. In the discussion below, we will use numbers from 0-6 in the place of weekdays. In particular:

Weekdays as numbers

0Sunday
1Monday
2Tuesday
3Wednesday
4Thursday
5Friday
6Saturday

Your program will only need to return the number, but for extra credit you can use a switch statement on the number to print out the day.

1. Finding The Doomsday Weekday for A Particular Year

First, we need to figure out what day all of the doomsdays fall on for a particular year, which we refer to as that year's doomsday. These steps may seem like magic, and a proof is beyond the scope of this assignment, but if you follow them diligently, you will get perfectly correct answers.

Century Anchor

First, we need to find the "century anchor" for the doomsday. This is a number between 0 and 6 that we add as an offset when figuring out the weekday for the year. The century anchor is computed as follows:

  1. Let c be the floor of of the year divided by 100. For example, for 1964, the century is 19 (you can get this with integer division, just as you got the number of buses on homework 1).
  2. Let x be (c % 4)*5
  3. The anchor is then computed as (x % 7 + 2) % 7

Finalizing Doomsday Year

Now we are ready to finalize the doomsday. For this, we will use what's referred to as the "Odd + 11 method."" To carry it out, follow these steps in sequence:

  1. Compute the anchor as above
  2. Let T be the 2-digit year (the remainder when dividing the year by 100). For instance, for 1974, T is 74.
  3. If T is odd, add 11
  4. Let T be T/2
  5. If T is odd, add 11.
  6. Let T be 7 - T % 7
  7. The doomsday for the year is (T + anchor) % 7
Steps 2-6 are shown in a flowchart on Wikipedia.

2. Find The Weekday (Finally!!)

For a particular date, expressed as month/day/year, we are now ready to find the day of the week of that date, expressed as a number. First, find the doomsday for the year, following the steps above. Call this ydoomsday. Then, given the month, find a known doomsday in that month, and count either forward or backward to it. In particular, the doomsdays for different months are shown in the table below. There are certainly more days than this that fall on the doomsday, but these ones were chosen so they would be easy to remember (e.g. 7/11 and 11/7, 9/5 and 5/9, 4/4, 6/6, 8/8, 10/10, 12/12)

January (1)If it's a leap year, 1/4, otherwise, 1/3
February (2)If it's a leap year, 2/29, otherwise, 2/28
March (3)3/7
April (4)4/4
May (5)5/9
June (6)6/6
July (7)7/11
August (8)8/8
September (9)9/5
October (10)10/10
November (11)11/7
December (12)12/12
We refer to the day of the week these all fall on in a particular year as ydoomsday. For instance, notice how in 2020, all of these days fall on a Saturday, so ydoomsday = 6. (Check your calendar...this will blow your mind). Call the particular day for a month reference. For instance, reference = 5 for September (you will have to hard code in the references to a series of if statements or a switch statement on the month). Since we know that reference occurs on ydoomsday, we count back to reference from our day of the month. Do this by creating a variable

diff = day - reference

Now add the year's doomsday offset ydoomsday to diff, and take the remainder after dividing by 7. If this remainder is negative, add 7. This is the final answer!!

Example 1

As an example, let's consider the day this assignment is due, 2/17/2020. As we discussed, the doomsday ydoomsday for 2020 is 6 (we could get this by the steps above). We're on a leap year in February, so the day reference is 29. Then, diff = 17 - 29 = -12. So we're 12 days before a Saturday. In code, -12 % 7 is -5, which is negative, so we add 7 to it to get 2. By our number to weekday table, this is a Monday! So our assignment is due on Monday, as usual.

Example 2

Consider the attack on Pearl Harbor, which took place on December 7, 1941. First, we compute the century anchor:

  1. c = 19
  2. (19 % 4)*5 is 15
  3. (15 % 7 + 2) % 7 is 3
So the century anchor for the 1900s is 3, or Tuesday. Now, let's compute the year offset.
  1. T = 41
  2. 41 is odd, so set T = 41 + 11 = 52
  3. T = 52/2 = 26
  4. 26 is not odd, so leave it as is
  5. T = 7 - 26 % 7, which is 2
Therefore, the ydoomsday for the 1941 year is 3+2ydoomsday or 5, a Friday. Next, we find the reference for the month of December, which is 12. The reference 12/12 of Friday is 5 days after our date of 12/7, so 12/7 must have been a Sunday. To see this following our procedure above, we compute
diff = 7 - 12 = -5
Since this is negative, we add 7 to it to get 2. Then, we add 2 + 5 (the doomsday for 1941) to get 7, which is 0 mod 7, which is a Sunday.

Programming Tasks (20 Points)

At a high level, your task is to compute the weekday of any date in the Gregorian calendar. To do this, you should fill in three methods HW3_WeekdayCalculator.java. You should do them one at a time and test each method thoroughly before proceeding to the next. This is to get you to practice modular code development, in which you break a complex task down into lots of small little tasks, or modules, that match a specification. In this assignment, there is no hope that getDoomsdayYear will work if getCenturyAnchor isn't working, and there is no hope that getWeekday will work if getCenturyAnchor isn't working. More details are below:

1. getCenturyAnchor(int c) (5 Points)

You are given the skeleton of a method whose job it is to compute a century anchor, given the digits of a century c. You should return a number between 0 and 6 corresponding to this century's anchor.

2. getDoomsdayYear(int year) (5 Points)

You should create a new method called getDoomsdayYear which takes as input a year, and which returns a number between 0 and 6 corresponding to the doomsday for that year. A proper implementation of this method should call getCenturyAnchor at some point to help with the calculation.

3. getWeekday(int year, int month, int day) (10 Points)

You should create a new method called getWeekday which takes as input the year, month (from 1 to 12), and day of a particular date, and which returns a number between 0 and 6 corresponding to the the number for the weekday of that day. A good implementation of this method should call getDoomsdayYear at some point. You should also look up the doomsday corresponding to the current month with a series of if/else statements or with a switch statement. You should use your isALeapYear function from lab 2 to check the special cases for January and February (feel free to copy and paste that function into this assignment).

Extra Credit (+2)

Create a method which takes as input a weekday as a number, and which returns a string corresponding to the actual day. Use this method to output the day as a word to the console.

Unit Tests (7 Points)

As always, testing is an important part of software development, and you will be graded on the quality of the tests you come up with. It is recommended that you create the tests as you are going along. You will need to create three sets of unit tests in the file tests/hw3_weekdaycalculator/HW3_WeekdayCalculatorTest.java.

  1. The first set is for getCenturyAnchor. You should add two centuries other than 1900 and 2000, which are provided.
  2. The next set of tests is for getDoomsdayYear. You will need to add at least 3 years in three different centuries in addition to 2020, which is already provided. Click here to see a bunch of examples of doomsdays for contemporary years.
  3. Finally, you will need to test the most important method of all, getWeekday. No test have been provided yet, but for the best coverage, you should add at least 12 tests spanning 12 different months. You can start with Peal Harbor day as your December test and the assignment due date as your February test. You may also want to add the day your were born, or some holiday some other year.

Style (3 Points)

You must adhere to the style guide as you are writing your code.