Question 1 (Methods and Control Structures)

The APCalendar class contains methods used to calculate information about a calendar. You will write two methods of the class.

public class APCalendar
{
    /** Returns true if year is a leap year and false otherwise. */
    private static boolean isLeapYear(int year)
    { /* implementation not shown */ }
    /** Returns the number of leap years between year1 and year2, inclusive.
     * Precondition: 0 <= year1 <= year2
     */
    public static int numberOfLeapYears(int year1, int year2)
    { /* to be implemented in part (a) */ }
    /** Returns the value representing the day of the week for the first day of year,
     * where 0 denotes Sunday, 1 denotes Monday, ..., and 6 denotes Saturday.
     */
    private static int firstDayOfYear(int year)
    { /* implementation not shown */ }
    /** Returns n, where month, day, and year specify the nth day of the year.
     * Returns 1 for January 1 (month = 1, day = 1) of any year.
     * Precondition: The date represented by month, day, year is a valid date.
     */
    private static int dayOfYear(int month, int day, int year)
    { /* implementation not shown */ }
    /** Returns the value representing the day of the week for the given date
     * (month, day, year), where 0 denotes Sunday, 1 denotes Monday, ...,
     * and 6 denotes Saturday.
     * Precondition: The date represented by month, day, year is a valid date.
     */
    public static int dayOfWeek(int month, int day, int year)
    { /* to be implemented in part (b) */ }
    // There may be instance variables, constructors, and other methods not shown.
}

Part (a)

Write the static method numberOfLeapYears, which returns the number of leap years between year1 and year2, inclusive.

In order to calculate this value, a helper method is provided for you.

  • isLeapYear(year) returns true if year is a leap year and false otherwise.

Complete method numberOfLeapYears below. You must use isLeapYear appropriately to receive full credit.

Answer

/** Returns the number of leap years between year1 and year2, inclusive.
* Precondition: 0 <= year1 <= year2 */
public static int numberOfLeapYears(int year1, int year2) {
    int currentYears = 0; // initializing integer leap year count variable
    for (int year = year1; year <= year2; year++) { // looping through years within range
        if (isLeapYear(year)) currentYears++; // incrementing currentYears per leap year
    }
    return currentYears;
}

See the code comments for explanations of each step of the process.

Part (b)

Write the static method dayOfWeek, which returns the integer value representing the day of the week for the given date (month, day, year), where 0 denotes Sunday, 1 denotes Monday, …, and 6 denotes Saturday. For example, 2019 began on a Tuesday, and January 5 is the fifth day of 2019. As a result, January 5, 2019, fell on a Saturday, and the method call dayOfWeek(1, 5, 2019) returns 6.

As another example, January 10 is the tenth day of 2019. As a result, January 10, 2019, fell on a Thursday, and the method call dayOfWeek(1, 10, 2019) returns 4.

In order to calculate this value, two helper methods are provided for you.

  • firstDayOfYear(year) returns the integer value representing the day of the week for the first day of year, where 0 denotes Sunday, 1 denotes Monday, …, and 6 denotes Saturday. For example, since 2019 began on a Tuesday, firstDayOfYear(2019) returns 2.
  • dayOfYear(month, day, year) returns n, where month, day, and year specify the nth day of the year. For the first day of the year, January 1 (month = 1, day = 1), the value 1 is returned. This method accounts for whether year is a leap year. For example, dayOfYear(3, 1, 2017) returns 60, since 2017 is not a leap year, while dayOfYear(3, 1, 2016) returns 61, since 2016 is a leap year.

Answer

/** Returns the value representing the day of the week for the given date
* (month, day, year), where 0 denotes Sunday, 1 denotes Monday, ...,
* and 6 denotes Saturday.
* Precondition: The date represented by month, day, year is a valid date.
*/
public static int dayOfWeek(int month, int day, int year) {
    return (firstDayOfYear(year) + dayOfYear(month, day, year) - 1) % 7;
}

Explanation

Despite being all one line, this statement has quite a bit of complexity.

I figured out that the most efficient way to determine the current day of the week is to use modulo division, combining the day of the week of the first day of the year and the day that’s being tested.

If you were to modulo divide the day of the week of the first day of the year by 7, you would get the same corresponding day of the year. However, if you were to add the nth day of the year to that number, the number corresponding to the day of the week would be offset forward by one day. If the first day of the year is a Sunday, the operation would be to add 1, n in this case, to the day of the week, 0, and the system would think the first day of the week was 1, or Monday. This is a day forward, so I corrected for this by subtracting 1.

Finished Code

I finished the class’s code below.

public class APCalendar
{
    /** Returns true if year is a leap year and false otherwise. */
    private static boolean isLeapYear(int year)
    {
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }
    /** Returns the number of leap years between year1 and year2, inclusive.
     * Precondition: 0 <= year1 <= year2
     */
    public static int numberOfLeapYears(int year1, int year2)
    {
        int currentYears = 0; // initializing integer leap year count variable
        for (int year = year1; year <= year2; year++) { // looping through years within range
            if (isLeapYear(year)) currentYears++; // incrementing currentYears per leap year
        }
        return currentYears;
    }
    /** Returns the value representing the day of the week for the first day of year,
     * where 0 denotes Sunday, 1 denotes Monday, ..., and 6 denotes Saturday.
     */
    private static int firstDayOfYear(int year)
    {
        // references for year and day of the week on Y2K
        int referenceYear = 2000;
        int referenceDayOfWeek = 6; // saturday
        int dayCount = 0;
        for (int y = referenceYear; y < year; y++) {
            dayCount += isLeapYear(y) ? 366 : 365; // calculating day count, each year since reference year
        }
        return (referenceDayOfWeek + dayCount) % 7; //calculating day of the week
    }
    /** Returns n, where month, day, and year specify the nth day of the year.
     * Returns 1 for January 1 (month = 1, day = 1) of any year.
     * Precondition: The date represented by month, day, year is a valid date.
     */
    private static int dayOfYear(int month, int day, int year)
    {
        int[] daysInMonth = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // array of month length
        if (isLeapYear(year)) {
            daysInMonth[2] = 29; // check for leap year
        }
        int dayOfYear = 0;
        for (int i = 1; i < month; i++) {
            dayOfYear += daysInMonth[i];
        }
        dayOfYear += day; // add the remaining days in the current month
        return dayOfYear;
    }
    /** Returns the value representing the day of the week for the given date
     * (month, day, year), where 0 denotes Sunday, 1 denotes Monday, ...,
     * and 6 denotes Saturday.
     * Precondition: The date represented by month, day, year is a valid date.
     */
    public static int dayOfWeek(int month, int day, int year)
    {
        return (firstDayOfYear(year) + dayOfYear(month, day, year) - 1) % 7;
    }
    // There may be instance variables, constructors, and other methods not shown.

    public static void main(String[] args) {
        String[] daysOfTheWeek = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

        // get user input
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter the month (1-12): ");
        int month = scanner.nextInt();
        System.out.print("\nEnter the day (1-31): ");
        int day = scanner.nextInt();
        System.out.print("\nEnter the year (e.g., 2023): ");
        int year = scanner.nextInt();
        scanner.close();
        // testing isLeapYear
        System.out.println("\n\nLeap year: " + (isLeapYear(year) ? "Yes" : "No"));
        // testing number of leap years
        System.out.println("Number of leap years since 1800: " + numberOfLeapYears(1800, year));
        // testing first day of year; should be 0 for Sunday
        System.out.println("Day of the week of January 1st, 2023: " + daysOfTheWeek[firstDayOfYear(year)]);
        // testing day of year of test date
        System.out.println("Day of the year of your date: " + dayOfYear(month, day, year));
        // testing the day of the week of September 20th, 2023 (should be Wednesday)
        System.out.println("Day of the week of your date: " + daysOfTheWeek[dayOfWeek(month, day, year)]);
    }
}

APCalendar.main(null);
Enter the month (1-12): 
Enter the day (1-31): 
Enter the year (e.g., 2023): 

Leap year: No
Number of leap years since 1800: 54
Day of the week of January 1st, 2023: Sunday
Day of the year of your date: 269
Day of the week of your date: Tuesday