Skip to main content

Leap Years

The challenge​

Write a function that takes an integer year and returns whether or not it is a leap year.

A leap year is one that is divisible by 4, but not divisible by 100 unless it is also divisible by 400.

For example:

  • 2001 is a typical common (non-leap) year.
  • 1996 is a typical leap year.
  • 1900 is an atypical common year (divisible by 100, but not 400).
  • 2000 is an atypical leap year (divisible by 100 and 400).

Remember to follow the red-green-refactor cycle and, if you're using an AI coding assistant, keep it on a tight leash — one test at a time.

Suggested test list​

  • A year not divisible by 4 at all (e.g. 2023) → not a leap year (happy path).
  • A year divisible by 4 and not by 100 (e.g. 1996) → leap year (happy path).
  • A year divisible by 100 but not by 400 (e.g. 1900) → not a leap year (the tricky rule).
  • A year divisible by 400 (e.g. 2000) → leap year (the tricky rule, other direction).
  • What about year 0? Decide whether your function should treat it as a valid input, and write a test that documents your decision.
  • What about negative years? Does the rule even make sense historically, and should your function reject them, or just apply the same arithmetic?
  • What is the smallest/largest input your language's integer type can represent — does your solution behave sensibly at those boundaries?

Your task​

Implement the solution using strict TDD, one test from the list at a time.

💡 Show a reference solution (only after you've completed your own via TDD)
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}

module.exports = { isLeapYear };
// example tests, e.g. with Jest
test("typical common year", () => expect(isLeapYear(2001)).toBe(false));
test("typical leap year", () => expect(isLeapYear(1996)).toBe(true));
test("atypical common year", () => expect(isLeapYear(1900)).toBe(false));
test("atypical leap year", () => expect(isLeapYear(2000)).toBe(true));