Leap Year Calculator
Level: Beginner 15–30 minConcepts: Validation
Solutions: C# | TypeScript | Python
Create a program to determine if a given year is a leap year.
Requirements
- Implement leap year rules:
- A year is a leap year if it is divisible by 4
- However, if the year is divisible by 100, it is not a leap year
- Unless the year is also divisible by 400, then it is a leap year
- Handle input validation:
- Input must be a positive integer
- Input must be a valid year (e.g., not negative)
- Return appropriate results:
- Boolean indicating if the year is a leap year
- Error message for invalid inputs
Test Cases
| Year | Is Leap Year? | Reason |
|---|---|---|
| 2000 | Yes | Divisible by 400 |
| 2004 | Yes | Divisible by 4, not by 100 |
| 2100 | No | Divisible by 100, not by 400 |
| 2001 | No | Not divisible by 4 |
| 0 | Error | Invalid year |
| -1 | Error | Invalid year |
Edge Cases to Consider
- Year 0
- Negative years
- Non-integer inputs
- Very large years
- Null or undefined inputs
Tips
- Start with the basic divisible by 4 rule
- Add the divisible by 100 exception
- Finally add the divisible by 400 rule
- Consider using a separate method for input validation
- Use descriptive variable names for the rules
Reference Walkthrough
Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/leap-year. Eight scenarios cover the full rule cascade — typical leap years (2020, 2024), century non-leap years (1900, 2100), four-hundred-divisible leaps (2000, 1600), and plain non-leap years (2001, 2023) — shared across all three languages, each a single pure function int → bool. Input validation concerns listed above (zero, negative years, non-integer inputs) are not implemented in the reference — the Gregorian rule cascade alone is sufficient to demonstrate the shape.
- C# (.NET 8, xUnit, FluentAssertions 6.12.0) — walkthrough
- TypeScript (Node 20, Vitest 1.6, TS 5 strict) — walkthrough
- Python (3.11, pytest) — walkthrough
This kata ships in Agent Full-Bake mode at high gear (F1 tier): the algorithm is small enough to land as one commit per language, with a brief walkthrough noting there are no builders because the algorithm’s inputs and outputs are the domain. No aggregates to construct, no value types to introduce, no collaborators to inject — just isLeapYear(year). See the repo’s Gears section for when high gear is the right call.