leap year
date calculation
calendar system
programming
leap year rules

Leap year calculation

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Leap year logic is easy to remember incorrectly and easy to ship with subtle bugs. The Gregorian calendar uses three rules that must be checked in the right order. Correct implementation matters for billing, scheduling, date validation, and month-length calculations.

Gregorian Leap-Year Rules

A year is leap if:

  • divisible by 4
  • except years divisible by 100 are not leap
  • except years divisible by 400 are leap

Equivalent evaluation order:

  1. If divisible by 400, leap.
  2. Else if divisible by 100, not leap.
  3. Else if divisible by 4, leap.
  4. Else not leap.

Century exceptions are where most bugs happen.

Correct Implementation Example

python
1def is_leap_year(year: int) -> bool:
2    if year % 400 == 0:
3        return True
4    if year % 100 == 0:
5        return False
6    return year % 4 == 0
7
8for y in [1900, 2000, 2024, 2025]:
9    print(y, is_leap_year(y))

Expected:

  • 1900 false
  • 2000 true
  • 2024 true
  • 2025 false

Use Leap Logic in Date Utilities

A common use case is days-in-month calculation.

python
1def days_in_month(year: int, month: int) -> int:
2    if month < 1 or month > 12:
3        raise ValueError("month out of range")
4
5    if month in [1, 3, 5, 7, 8, 10, 12]:
6        return 31
7    if month in [4, 6, 9, 11]:
8        return 30
9    return 29 if is_leap_year(year) else 28
10
11print(days_in_month(2024, 2))
12print(days_in_month(2025, 2))

This function is deterministic and easy to test.

Why the Century Rule Exists

If calendar used only every-four-years logic, average year length would be too long and civil dates would drift relative to seasons. Gregorian correction improves long-term alignment.

In software terms, this means historical calendar decisions directly affect modern data correctness. Incorrect leap logic can silently skew month-based analytics and legal deadlines.

Prefer Library Functions for Full Date Arithmetic

For full date arithmetic, built-in libraries are safer than hand-written date math.

python
1import calendar
2
3print(calendar.isleap(2024))
4print(calendar.monthrange(2024, 2)[1])

Use custom leap logic only when required by lightweight utility constraints or interview-style algorithms.

Testing Strategy That Catches Real Bugs

Minimum test classes:

  • divisible by 4 only
  • divisible by 100 but not 400
  • divisible by 400
  • not divisible by 4
python
1def test_leap_cases():
2    cases = {
3        1996: True,
4        1999: False,
5        1900: False,
6        2000: True,
7    }
8    for year, expected in cases.items():
9        assert is_leap_year(year) == expected
10
11
12test_leap_cases()

These edge cases prevent almost every common implementation bug.

Domain Scope and Historical Data

Gregorian rules are standard for modern software systems, but historical datasets can involve calendar transitions by country and period. If your product handles archival records, define calendar policy explicitly and use specialized libraries.

Do not assume one calendar model fits all historical business domains.

Practical API Validation Use Case

Many APIs accept date fields as year, month, and day strings. Leap-year checks should be integrated with full date validation, not executed in isolation. For example, 2025-02-29 should be rejected while 2024-02-29 is valid.

Keeping leap-year logic centralized in a shared validation utility avoids duplicated date bugs across multiple endpoints and services.

Performance Considerations

Leap checks are constant-time and extremely cheap. Performance concerns usually come from repeated date parsing or large loops around I O, not from modulo operations themselves.

Optimize surrounding workflow before trying to micro-optimize leap logic.

Common Pitfalls

  • Implementing leap as only divisible-by-four and ignoring century exceptions.
  • Checking % 4 before % 100 and % 400 with wrong branching logic.
  • Testing random years but skipping 1900 and 2000 boundary checks.
  • Reimplementing complete date arithmetic when standard libraries already handle it.
  • Applying Gregorian assumptions to historical records without domain review.

Summary

  • Leap-year correctness depends on the three Gregorian divisibility rules.
  • Century years are the critical boundary to test.
  • Keep leap logic centralized in one tested utility function.
  • Use built-in date libraries for full calendar arithmetic.
  • Document calendar assumptions when data can include historical periods.

Course illustration
Course illustration

All Rights Reserved.