ExamplesBy LevelBy TopicLearning Paths
1122 Fundamental

1122-leap-year — Leap Year

Functional Programming

Tutorial

The Problem

A leap year in the Gregorian calendar occurs every 4 years, except for centuries (divisible by 100), which are only leap years if also divisible by 400. The rule has three conditions arranged in a specific priority: (divisible by 4) AND NOT (divisible by 100) OR (divisible by 400). This is a classic exercise in boolean logic and is the first date-calculation building block.

The Gregorian calendar reform in 1582 introduced this rule to keep the calendar aligned with the solar year (365.2425 days). Software that handles dates — from scheduling systems to financial calculations — must implement this rule correctly.

🎯 Learning Outcomes

  • • Implement the three-part leap year rule correctly
  • • Express the rule as a boolean formula with correct operator precedence
  • • Write comprehensive tests covering all four cases (regular, century, leap century, non-leap)
  • • Understand why the rule exists (solar year alignment)
  • • Handle edge cases: year 0 (proleptic Gregorian), negative years
  • Code Example

    #![allow(clippy::all)]
    //! Stub to satisfy cargo.
    pub fn stub() {}

    Key Differences

  • Operator precedence: Both && binds tighter than || in Rust and OCaml, making the formula a || (b && c) without explicit parentheses — but adding them improves clarity.
  • Integer division: Both use remainder (% / mod) for the divisibility checks; negative years behave differently in each language's modulo semantics.
  • **chrono crate**: Production Rust uses the chrono crate for date calculations; OCaml uses Calendar or Ptime.
  • Calendar systems: The Gregorian rule applies to years > 1582; proleptic Gregorian extends it backward — chrono handles this, raw implementations often do not.
  • OCaml Approach

    let is_leap_year year =
      year mod 400 = 0 || (year mod 4 = 0 && year mod 100 <> 0)
    

    Identical logic. OCaml uses mod instead of % and <> instead of != for not-equal, but the boolean structure is the same.

    Full Source

    #![allow(clippy::all)]
    //! Stub to satisfy cargo.
    pub fn stub() {}

    Exercises

  • Write days_in_month(year: i32, month: u32) -> u32 using is_leap_year for February.
  • Implement day_of_year(year: i32, month: u32, day: u32) -> u32 that returns the ordinal day (1–365/366).
  • Write a property-based test using quickcheck that verifies is_leap_year matches the chrono crate's answer for all years from 1 to 9999.
  • Open Source Repos