Why does Earth's orbit force us to add a day?

Earth takes roughly 365.2422 days to circle the Sun. A standard year runs 365 days. That leftover fraction stacks up. Ignore it, and the seasons slide: after a few centuries, summer would land in December, and July would sit in northern-hemisphere winter.

Ancient civilizations spotted the drift. The Egyptian calendar slipped a full day every four years. Julius Caesar imposed a fix: add an extra day every fourth year. The Julian calendar was born. But it overcorrected. It assumed the orbital year was exactly 365.25 days, not 365.2422. That tiny overshoot per year added up to roughly 10 days by the 1500s.

How do you know if a year is a leap year?

Pope Gregory XIII rolled out the Gregorian calendar in 1582 to stop the drift. Three conditions decide it:

  • A year is a leap year if it divides evenly by 4.
  • But if it divides evenly by 100, it is not.
  • Unless it also divides evenly by 400. Then it is again.

So 2000 was a leap year. 1900 was not. 2100 will not be.

This formula trims the average year to 365.2425 days. Close enough to the astronomical 365.2422 that the remaining gap grows by about one day every few thousand years. The Gregorian calendar is the de facto global civil standard.

One consequence: the ordinal date, written YYYY-DDD, where DDD runs from 1 to 366. In a non-leap year, December 31 is day 365. In a leap year, it is day 366. February 29 is day 60. The day-of-year system is part of ISO 8601 and works well for log files, scientific data, and any context where month names add ambiguity.

What breaks in code when February has 29 days?

The rule is simple. The edge cases are not. They have caused real outages.

On February 29, 2012, Microsoft Azure suffered a widespread service disruption. Cloud storage failed because certificate validation code rejected the date as invalid. Amazon Web Services hit a similar problem that year in its S3 blob storage. Both cases shared a root cause: code that assumed February always has 28 days.

Another pattern: systems that store a date as month and day, then reuse it for the next year. If that date is February 29 and the following year is not a leap year, the system breaks. This hits recurring billing, anniversary calculations, and cron jobs.

ISO 8601 week numbering adds a twist. The week-numbering year can differ from the calendar year. January 1 may belong to the last week of the previous year. December 31 may land in week 1 of the next. The ISO 8601 standard spells out the rule: week 1 is the week containing the year's first Thursday. A leap year does not directly alter week numbers, but the day count in the final week can shift.

Leap seconds vs leap years: two different corrections

Leap years and leap seconds solve different problems. They are often confused.

Leap years correct for Earth's orbital period around the Sun. Leap seconds correct for Earth's rotation slowing down. The planet's spin is not perfectly constant. Since 1972, the International Earth Rotation and Reference Systems Service has inserted 27 leap seconds to keep atomic time (UTC) within 0.9 seconds of astronomical time (UT1). The most recent insertion was December 31, 2016.

Leap seconds are a separate phenomenon with their own set of bugs. They are covered in the leap seconds explainer. The key difference: leap years are predictable centuries ahead. Leap seconds are unpredictable and announced only six months in advance.

How to check for a leap year in code

The logic is straightforward. In Python:

python def is_leap_year(year): if year % 400 == 0: return True if year % 100 == 0: return False return year % 4 == 0

In JavaScript:

javascript function isLeapYear(year) { return (year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0); }

Many standard libraries already handle this. In Python, calendar.isleap(year) returns the correct boolean. In Java, Year.isLeap(year) from the java.time package works. In JavaScript, the Date object handles February 29 correctly when constructing dates. But be careful: constructing new Date(2023, 1, 29) (February 29, 2023) silently rolls to March 1 instead of throwing an error. That silent rollover has caused production bugs.

Famous leap year bugs

Beyond the Azure and AWS outages in 2012, notable cases include:

  • 2000: Many systems storing dates as two-digit years (YY) assumed 2000 was not a leap year because 00 was treated as 1900. This was part of the broader Y2K problem. The root cause was year truncation, not the century rule itself.

  • 2008: A leap year bug in the Android operating system crashed calendar apps on February 29. The bug lived in the date-picker component used by multiple apps.

  • 2016: Several European banking systems failed to process transactions scheduled for February 29. Batch processing code assumed 365 days per year and overflowed when it hit day 366.

  • 2020: Some Salesforce CRM versions mishandled February 29 in recurring date formulas, causing missed follow-up tasks for sales teams.

The Year 2038 problem is different: a signed 32-bit integer overflow in Unix time, not a leap year issue. Both are time-related time bombs that developers need to know.

When is the next leap year, and what is changing?

The next leap year is 2028. The bigger shift is the planned abolition of leap seconds. In November 2022, the General Conference on Weights and Measures voted to eliminate leap seconds by 2035, replacing them with a larger correction at longer intervals, possibly a leap minute by around 2135. After 2035, UTC will no longer be tied to Earth's rotation. For most people, daily life will not change. For anyone writing high-precision time code, the rules change. The UTC explainer has more detail.

Leap years are not going away. The Gregorian rule will serve for thousands of years before the remaining drift matters. The correct mental model: a year divisible by 4, unless it is a century not divisible by 400.