Check Leap Year in PHP

Beginner
⏱️ 8 min read
📚 Updated: May 2026
🎯 2 Code Examples
Gregorian

What you’ll learn

  • The Gregorian leap rule: divisible by 4, except most centuries, unless divisible by 400.
  • A compact isLeapYear predicate in clean PHP style.
  • Printing every leap year in 2024–2050 (matching the reference output) plus a live preview.

Overview

Leap years keep the civil calendar aligned with the tropical year by inserting an extra day (February 29). The decision rule is pure integer modular arithmetic—ideal for a short if chain in PHP.

Two programs

2024 single check and 2024–2050 listing.

Live preview

Integer years in a safe range; same predicate as the PHP examples.

Rigor

Century vs quadricentennial cases and adoption caveats in the FAQ.

Prerequisites

The modulo operator %, boolean && and ||, and for loops.

  • Basic PHP syntax, if conditions, and echo.
  • Operator precedence: % binds tighter than ==; parentheses keep the intent obvious.

What is a leap year?

In the Gregorian calendar, a year is a leap year if February has 29 days. The arithmetic rule fixes the drift of a pure 365-day year.

Every year divisible by 4 is a leap candidate; century years (% 100 == 0) are ruled out unless they are divisible by 400.

2024 %4, not %100
1900 %100, not %400
2000 %400

Predicate

Let L(y) be true iff (y mod 4 = 0 ∧ y mod 100 ≠ 0) ∨ (y mod 400 = 0). Then L(y) is the standard proleptic Gregorian leap-year predicate.

2024

2024 mod 4 = 0 and 2024 mod 100 = 24 ≠ 0, so L(2024) holds.

Intuition

2024 Leap
Rule
quadrennial, not a century exception
2021 Common
Rule
2021 mod 4 = 1

Takeaway: divisibility by 4 is necessary but not sufficient once centuries enter the picture.

Live preview

Integer years in a reasonable safe range (this widget uses |y| ≤ 1000000).

Try 2000, 1900, or 2021.

Live result
Press “Check leap”.

Algorithm

Goal: evaluate the Gregorian leap predicate for an integer year.

Quadrennial test

Check year % 4 == 0. If false, the year is common.

Century refinement

If year % 100 == 0, require year % 400 == 0 to remain leap; otherwise the century exception applies.

📜 Pseudocode

Pseudocode
function isLeapYear(y):
    return (y mod 4 = 0 and y mod 100 != 0) or (y mod 400 = 0)
1

Single year: 2024

Same condition as the reference, written in clean PHP.

c
<?php
function isLeapYear(int $year): bool
{
    return ($year % 4 === 0 && $year % 100 !== 0) || ($year % 400 === 0);
}

$year = 2024;

echo isLeapYear($year)
    ? "$year is a leap year.\n"
    : "$year is not a leap year.\n";
?>

Explanation

Short-circuiting && and || match the usual truth table; parentheses mirror the prose rule.

2

Leap years in [2024, 2050]

Matches the reference bounds and output line.

c
<?php
function isLeapYear(int $year): bool
{
    return ($year % 4 === 0 && $year % 100 !== 0) || ($year % 400 === 0);
}

$startYear = 2024;
$endYear = 2050;

echo "Leap years in the range $startYear to $endYear:\n";
for ($year = $startYear; $year <= $endYear; $year++) {
    if (isLeapYear($year)) {
        echo $year . " ";
    }
}
echo "\n";
?>

Explanation

Leap years spaced by 4 until a century boundary; 2100 would break the pattern, but this interval stops at 2050.

Alternatives

Lookup tables. For a fixed window (like a UI calendar), precompute leap flags once.

Date libraries. Production systems often delegate to mktime / platform APIs after validating components.

Interview: recite the 4 / 100 / 400 rule cleanly; mention real-world adoption only if asked.

❓ FAQ

A year is a leap year if it is divisible by 4, except years divisible by 100, unless they are also divisible by 400. Equivalently: leap iff (y%4==0 && y%100!=0) || (y%400==0).
Yes. 2000 is divisible by 400, so it is a leap year even though it is divisible by 100.
No. 1900 is divisible by 100 but not by 400, so it is a common year.
No. Adoption dates differ by country, and other calendars use different rules. This page uses the usual proleptic Gregorian arithmetic for integer years.
Historical numbering is messy; in code, define how you want to treat non-positive years and keep your rule consistent. This tutorial keeps examples to typical positive civil years.
A single test is O(1) arithmetic. Scanning a year range [a,b] costs O(b - a + 1) with O(1) extra space.

🔄 Input / output examples

Change year in Example 1 or start_year / end_year in Example 2.

YearLeap?
2024Yes
2021No
2000Yes
1900No

Edge cases and pitfalls

The predicate is only part of a full date library; validating month/day and time zones is separate work.

400

Quadricentennial leap

2400 will be leap; 2200 will not.

BC

Astronomical year 0

Do not mix astronomical 0 with historical 1 BC without a clear convention.

Range

start > end

Swap bounds or guard the loop to avoid empty or inverted scans.

Types

int width

Typical int is plenty for civil years; use wider types only if you embed years in packed timestamps.

⏱️ Time and space complexity

TaskTimeExtra space
One yearO(1)O(1)
Range [a, b]O(b - a + 1)O(1)

No auxiliary memory is required beyond loop indices.

Summary

  • Rule: (y%4==0 && y%100!=0) || (y%400==0).
  • Code: one boolean function plus a simple range loop for listings.
  • Watch-outs: Gregorian adoption history, negative years with %, and consistent range prose.
Did you know?

The Julian calendar had a leap every four years without the century exception. The Gregorian reform (1582 in several countries) dropped 10 days and refined the rule so years like 1900 are common years while 2000 stays a leap year.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful