APCalendar: 2019 FRQ 1
A step-by-step solution to the 2019 AP CSA FRQ 1 (APCalendar), covering a counting loop and combining two given helper methods to compute a day of the week in Java.
Calendars hide a surprising amount of arithmetic behind a simple question like "what day of the week was this?" This AP Computer Science A free-response question asks you to count leap years across a range, then combine two given helper methods to work out a day of the week without writing any date logic of your own.
What This FRQ Tests
- AP CSA units: Unit 3 (Boolean Expressions and if Statements), Unit 4 (Iteration), Unit 5 (Writing Classes/methods)
- Core skill: writing a counting loop that calls a boolean helper method once per iteration
- Secondary skill: combining two independent helper methods' results with plain arithmetic instead of re-deriving their logic
- Official category: "Methods and Control Structures" — always FRQ 1 on the AP CSA exam
The Setup
APCalendaris a utility class — every method isstatic, and there are no instance variables at all.private static boolean isLeapYear(int year)— given, not to modify.public static int numberOfLeapYears(int year1, int year2)— part (a).private static int firstDayOfYear(int year)— given; returns 0-6 for the weekday January 1 fell on.private static int dayOfYear(int month, int day, int year)— given; returns which numbered day of the year a date is (Jan 1 = 1), already accounting for leap years.public static int dayOfWeek(int month, int day, int year)— part (b).
Part (a): Writing numberOfLeapYears(int year1, int year2)
Step-by-Step Approach
- Start a counter at
0. - Loop over every year from
year1toyear2, inclusive. - Call
isLeapYear(year)on each one. - If it returns
true, increment the counter. - Return the counter after the loop ends.
The Code
public static int numberOfLeapYears(int year1, int year2)
{
int count = 0;
for (int year = year1; year <= year2; year++)
{
if (isLeapYear(year))
{
count++;
}
}
return count;
}
Why Each Piece Matters
year <= year2, not<— the precondition says the range is inclusive, soyear2itself must be checked, never skipped.- Calling
isLeapYear(year)instead of reimplementing leap-year logic — the question's real rubric explicitly requires using the helper "appropriately" to receive full credit.isLeapYearalready exists and is assumed correct; there's no reason (and no credit) for rewriting the "divisible by 4, not by 100 unless by 400" rule inline. countonly changes inside theifblock — years that aren't leap years simply pass through the loop with no effect on the total.
Tracing the Example
The released question doesn't give a numeric example for this specific method, but it's easy to self-check using a small range: numberOfLeapYears(2016, 2019).
| Year | isLeapYear(year) |
Running count |
|---|---|---|
| 2016 | true | 1 |
| 2017 | false | 1 |
| 2018 | false | 1 |
| 2019 | false | 1 |
The loop returns 1 — the only leap year in that range is 2016, which checks out.
Common Mistakes to Avoid
- Using
<instead of<=. This silently skipsyear2, undercounting by one wheneveryear2itself happens to be a leap year. - Reimplementing the leap-year rule inline instead of calling
isLeapYear. Even if the logic is correct, it ignores the instruction to use the helper, and risks getting the actual rule (the "divisible by 100 but not 400" exception) subtly wrong. - Starting
countat1out of habit — there's no reason to assume the range starts on a leap year.
Part (b): Writing dayOfWeek(int month, int day, int year)
The Rule, Broken Down
firstDayOfYear(year)tells you which weekday (0-6) January 1 fell on that year.dayOfYear(month, day, year)tells you which numbered day of the year this date is (January 1 is day 1).- Since day 1 falls on weekday
firstDayOfYear(year)exactly, every day after that shifts the weekday forward by one, wrapping every 7 days.
Step-by-Step Approach
- Get the year's starting weekday:
first = firstDayOfYear(year). - Get this date's day number within the year:
n = dayOfYear(month, day, year). - Day 1 corresponds to weekday
firstexactly, so dayncorresponds to weekdayfirst + (n - 1)— the-1because day 1 itself shouldn't add any offset. - Wrap that sum into the valid 0-6 range with
% 7.
The Code
public static int dayOfWeek(int month, int day, int year)
{
int first = firstDayOfYear(year);
int n = dayOfYear(month, day, year);
return (first + n - 1) % 7;
}
Why Each Piece Matters
n - 1counts how many days after January 1 this date is — day 1 itself should add zero days, not one.- Adding that offset to
firstshifts the year's starting weekday forward by the right number of days. % 7keeps the result inside the valid 0-6 range no matter how largefirst + n - 1gets — a year has up to 366 days, so the raw sum can be far bigger than 7, and it needs to wrap around correctly.
Tracing the Example
The question states firstDayOfYear(2019) returns 2 (2019 began on a Tuesday), and gives two worked calls:
| Call | first |
n (dayOfYear) |
first + n - 1 |
% 7 |
Expected |
|---|---|---|---|---|---|
dayOfWeek(1, 5, 2019) |
2 | 5 | 6 | 6 | 6 |
dayOfWeek(1, 10, 2019) |
2 | 10 | 11 | 4 | 4 |
Both match the question's stated return values exactly — 6 (Saturday) and 4 (Thursday).
Common Mistakes to Avoid
- Forgetting the
- 1. Addingfirst + ndirectly overcounts by one day, since day 1 shouldn't add any offset at all. - Applying
% 7at the wrong step — the full sumfirst + n - 1needs to be computed first, then reduced mod 7, not the other way around. - Trying to recompute the day-of-year or first-day-of-year logic manually instead of calling the two given helper methods. Both are already provided, correct, and exactly what "must use
firstDayOfYearanddayOfYearappropriately" is asking for.
Key Takeaways
- "Inclusive" in a precondition is a direct signal to use
<=, not<, in a loop's bound. - When a problem hands you working helper methods, the intended solution almost always combines their results with simple arithmetic rather than re-deriving their logic yourself.
- Modular arithmetic (
% 7for weekdays, or% nfor any fixed-size cycle) is the standard tool for wrapping a running offset back into a valid range.