Learning Objectives
- Understand why the Gregorian calendar has irregular month lengths, especially February's 28/29-day anomaly
- Learn the historical path from the Julian calendar to the Gregorian reform and how it shaped the 400-year leap rule
- Identify why February 29 is the highest-risk date in any date-handling system and what test cases it implies
The Astronomical Problem
The Earth takes approximately 365.2422 days to orbit the Sun — not a whole number. Any calendar based on 365 days per year will drift out of sync with the seasons by about one day every four years. After 128 years, what was spring is now winter.
The Romans tried to fix this with the Julian calendar (introduced by Julius Caesar in 46 BCE), which adds a leap day every four years without exception. Simple, but not quite right: the actual solar year is slightly shorter than 365.25 days, so the Julian calendar gains about 11 minutes per year. After 400 years, that's three extra days.
The Gregorian Reform
By 1582, the Julian calendar had drifted 10 days ahead of the astronomical calendar. Pope Gregory XIII commissioned a correction. The Gregorian calendar introduced a refined rule:
- A year is a leap year if divisible by 4
- Except century years (divisible by 100), which are not leap years
- Unless the century year is also divisible by 400, which is a leap year
This means:
| Year | Leap? | Reason |
|---|---|---|
| 1900 | No | Divisible by 100, not by 400 |
| 2000 | Yes | Divisible by 400 |
| 2100 | No | Divisible by 100, not by 400 |
| 2024 | Yes | Divisible by 4, not a century |
Why February Specifically?
In the original Roman calendar, February was the last month of the year. When the calendar was reformed, the intercalary (leap) day was inserted into February as a political and religious decision — not a mathematical one. The other months had already been fixed and named. February drew the short straw.
The result: February has 28 days in common years and 29 in leap years. Every other month has either 30 or 31 days. February is the only month whose length is variable, and this variability is governed by a three-condition rule most programmers don't memorize correctly.
What This Means for Testers
February 29 is the single most dangerous date in any system that stores or calculates dates. Consider what happens to a user born on February 29, 2000 when a system tries to calculate their age, schedule their annual review, or send their birthday email. If the system naively adds "1 year" to February 29, it produces February 29 of a non-leap year — a date that doesn't exist.
Key test cases every system with date fields needs:
- Submit
1900-02-29— this should be rejected (1900 is NOT a leap year) - Submit
2000-02-29— this should be accepted (2000 IS a leap year) - Submit
2100-02-29— this should be rejected (2100 is NOT a leap year) - Submit
2024-02-29— this should be accepted (2024 IS a leap year) - Submit
2023-02-29— this should be rejected (2023 is a common year)
The bug pattern to watch for: a system that accepts 1900-02-29 is using the simplified "divisible by 4" rule and ignoring the century exception.