Learning Objectives
- Memorize the exact three-condition Gregorian leap year algorithm and understand why each condition exists
- Identify the most common implementation errors: the 1900/2000 confusion and the century exception omission
- Design a minimal test suite that distinguishes correct from broken leap year implementations
The Complete Algorithm
The Gregorian leap year rule has exactly three conditions, applied in order:
isLeapYear(year):
if year % 400 == 0: return true // 400-year exception
if year % 100 == 0: return false // century exception
if year % 4 == 0: return true // basic rule
return false
This is not the same as year % 4 == 0. That simplified rule is wrong for century years. The correct algorithm requires checking divisibility by 400 before checking divisibility by 100.
The Most Common Implementation Bug
The most frequent mistake is implementing only the first condition:
// WRONG — misses the century exception
boolean isLeap = (year % 4 == 0);
// WRONG — gets centuries right, misses the 400-year override
boolean isLeap = (year % 4 == 0) && (year % 100 != 0);
// CORRECT
boolean isLeap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
The second wrong implementation will correctly identify 2100 as non-leap, but will incorrectly identify 2000 as non-leap — a bug that was invisible for 400 years and briefly visible in the year 2000.
The 1900 vs 2000 Test Case
The canonical test case for leap year bugs is the 1900/2000 pair:
| Year | Correct answer | Simple (÷4 only) | No-400 rule |
|---|---|---|---|
| 1900 | NOT leap | Leap (wrong) | NOT leap (correct) |
| 2000 | Leap | Leap (correct) | NOT leap (wrong) |
A system that accepts 1900-02-29 has the simple bug. A system that rejects 2000-02-29 has the no-400 rule bug. These are different bugs with different root causes.
Off-By-One Errors in Date Calculations
Leap year bugs don't only affect February 29 input validation. They also appear in date arithmetic:
- "What is one year after 2000-02-29?" — a correct implementation returns
2001-02-28; a broken one may return March 1 or crash - "How many days between 1999-01-01 and 2001-01-01?" — must include the 366 days of leap year 2000
Testing Strategy
A minimal test suite for leap year validation needs exactly five cases:
| Input | Expected | Tests |
|---|---|---|
2024-02-29 |
Valid | Basic divisible-by-4 case |
2023-02-29 |
Invalid | Non-leap year |
2000-02-29 |
Valid | 400-year override (catches no-400 bug) |
1900-02-29 |
Invalid | Century exception (catches simple-rule bug) |
2100-02-29 |
Invalid | Future century exception |
These five cases form a decision table that uniquely identifies which variant of the leap year bug is present in a system.