Dates & time

Leap years, lost days and why calendars are hard

A year is not 365 days, and it is not 365.25 either. Every calendar rule we have is an attempt to paper over that gap.

· 8 min read

The Earth takes about 365.2422 days to orbit the Sun. That number — not quite a whole number, not quite a neat fraction — is the source of every calendar complication humans have ever invented, and of a surprising number of software bugs.

If you ignore the leftover 0.2422 of a day, your calendar drifts by about a day every four years. Within a few centuries your harvest festival lands in midwinter. Every fix we have ever adopted is an approximation of that awkward fraction.

The first fix, and why it wasn't enough

Julius Caesar's reform in 46 BC took the obvious approach: 0.2422 is close to a quarter, so add one extra day every four years. The Julian calendar assumed a year of exactly 365.25 days.

That is very close, but it is 11 minutes and 14 seconds too long. Eleven minutes a year sounds negligible — and it is, for a lifetime. Over centuries it accumulates at roughly one day every 128 years. By the 1500s the calendar had drifted about ten days out of step with the seasons, which mattered enormously to the Church, because the date of Easter is calculated from the spring equinox.

The Gregorian rule

Pope Gregory XIII's 1582 reform kept the four-year rule but added exceptions to remove the excess:

So 1996 and 2024 are leap years. 1700, 1800 and 1900 were not. 2000 was — because it is divisible by 400 — which is why the rule caught out so many people and so much software in living memory. 2100 will not be.

This gives an average year of 365.2425 days against the true 365.2422 — an error of about 27 seconds a year, or one day in roughly 3,200 years. Good enough that nobody needs to worry about it.

The eleven days Britain skipped

Adopting the new calendar meant deleting the accumulated drift, and countries did it at wildly different times. Catholic Europe moved in 1582, jumping straight from 4 October to 15 October — ten days that simply never existed.

Protestant Britain held out until 1752, by which point the gap had grown to eleven days. Wednesday 2 September 1752 was followed by Thursday 14 September 1752. The same act moved the start of the legal year from 25 March to 1 January.

The practical upshot is a genuine trap for anyone working with historical dates: between 1582 and 1752, a date recorded in England and the same date recorded in France refer to different days. Russia did not switch until 1918 — which is why the "October Revolution" happened in November by our calendar. Greece was last in Europe, in 1923.

This is also why date libraries behave oddly before 1582, and why many refuse to guess: there is no single correct answer without knowing which country's records you are reading.

Why your birthday moves a weekday

An ordinary year is 365 days, which is 52 weeks plus one day. That leftover day is why any fixed date lands one weekday later the following year — a Monday birthday becomes a Tuesday.

A leap year adds a second extra day, so dates after 29 February jump forward by two weekdays instead of one. That is the whole mechanism. Over a 28-year cycle the pattern repeats — though the century exceptions disturb it, so the full Gregorian cycle is actually 400 years, containing 146,097 days. Conveniently, that is exactly 20,871 weeks, which means the entire calendar repeats every 400 years and 1 January 2000 fell on the same weekday as 1 January 1600.

Worth separating clearly: the weekday of the date you were born never changes. It is fixed in history. What moves is the weekday of each subsequent anniversary.

Being born on 29 February

Roughly one person in 1,461 is a "leapling," born on a date that exists only once every four years. Legally, most jurisdictions treat the anniversary as 1 March in common years — for majority, licensing and similar thresholds — though some use 28 February. In practice most leaplings celebrate on whichever they prefer and enjoy the novelty of a technically-correct age one quarter of everyone else's.

It also causes genuine software problems. Any system that computes an anniversary by substituting the current year into a stored date will produce 29 February 2026 — a date that does not exist — and either throw an error or silently roll to 1 March. This class of bug reliably surfaces every four years.

Date bugs that reached production

The 1900 leap year that never was. Lotus 1-2-3 incorrectly treated 1900 as a leap year. When Microsoft built Excel, it deliberately reproduced the bug for file compatibility — and it is still there today. Excel believes 29 February 1900 existed. Every date calculation crossing that boundary is off by one, and it has never been fixed because too much depends on the wrong behaviour.

Y2K. Storing years as two digits saved expensive memory in the 1960s and 70s, but made 2000 indistinguishable from 1900. The reason so little went wrong is that an enormous amount of remediation work happened first — the quiet success is often mistaken for the problem having been imaginary.

Year 2038. Unix systems traditionally count seconds since 1 January 1970 in a signed 32-bit integer. That overflows on 19 January 2038, wrapping to 1901. Modern systems use 64-bit time, but embedded devices with long service lives are still being manufactured with 32-bit time today.

Time zones and DST. Not strictly calendar maths, but the same family of problem. Some days have 23 hours, some have 25. Some local times occur twice; some never occur at all. Time zone rules change by political decision, sometimes with weeks of notice, which is why the IANA time zone database is updated several times a year and why hard-coding an offset is always a mistake.

Practical rules for working with dates

Never write your own date arithmetic. Every language has a well-tested date library that already handles leap years, month lengths, time zones and DST. Manual arithmetic based on "365 days" or "30 days in a month" is wrong the moment it crosses a boundary.

Store in UTC, display in local. Keep one unambiguous representation internally and convert only at the edges, when showing something to a person.

Use ISO 8601 — YYYY-MM-DD. Is 03/04/2026 the third of April or the fourth of March? It depends who wrote it. 2026-04-03 is unambiguous everywhere, and sorts correctly as plain text.

Be precise about what you are counting. "One month from 31 January" has no obvious answer, and different libraries make different choices. Age in whole years, age in months and days, and elapsed days are three different questions — decide which one you actually need before computing it.

Test the awkward dates. 29 February, 31 December, the DST changeover, 1 March in a leap year and the year boundary catch the overwhelming majority of date bugs. They are five test cases and they are worth writing.

The underlying lesson is that calendars are not a mathematical system. They are an accumulated political and religious settlement, patched repeatedly over two millennia to track an orbit that does not divide neatly into days. Treat them with the suspicion that history deserves.

Tools mentioned in this guide