Start learning free

LESSON 90 OF 414 · CONDITIONAL STATEMENTS - CHALLENGES

Leap Year in Rust: Chained if Statements and %

Practice Read the full explanation

A leap year happens every four years, so it's a year that is perfectly divisible by four.

However, if the year is a multiple of 100 (1800, 1900, etc), the year must be divisible by 400 to be leap.

Write a function that determines if the year is a leap year or not.

Examples:

year = 2020 ➞ true

year = 2021 ➞ false

year = 1968 ➞ true

year = 1900 ➞ false

Video Solution:

STEP 1 OF 4
    Ctrl + Enter to check

    RUST · CONDITIONAL STATEMENTS - CHALLENGES

    Leap Year in Rust, explained

    Problem overview

    The function is_leap_year takes a year as an i32 and returns a bool: true for a leap year and false otherwise. The rule has two layers. A year divisible by 4 is a leap year, but a century year, one divisible by 100, is a leap year only when it is also divisible by 400.

    Examples: 2020 and 1968 are leap years because they divide by 4 and aren't centuries. 2021 doesn't divide by 4. 1900 divides by 4 and by 100 but not by 400, so it is not a leap year. 2000 divides by 400, so it is.

    Approach

    The rule is easier to code as a chain of checks, from the most specific exception to the general case, where each check ends the function when it applies. The order matters, because each later check can assume the earlier ones failed:

    1. Divisible by 400: always a leap year. Such a year is also divisible by 100 and by 4, so this must come first. Otherwise the century check would reject 2000.
    2. Divisible by 100 (and, having failed the first check, not by 400): not a leap year.
    3. Divisible by 4 (and, having failed the first two, not a century): a leap year.
    4. Anything left isn't divisible by 4: not a leap year.

    A shorter way to write the same logic is one expression, year % 4 == 0 && (year % 100 != 0 || year % 400 == 0). The chain is longer but each line maps to one sentence of the rule.

    Trace three years through the chain. For 2000, the first check succeeds (2000 % 400 is 0), so the function returns true at once. For 1900, 1900 % 400 is 300, so the first check fails. Then 1900 % 100 is 0, so the function returns false. For 1968, the remainders by 400 and by 100 are 368 and 68, both nonzero, and 1968 % 4 is 0, so the third check returns true. Each year leaves through exactly one return.

    The test inputs are plain i32 values, so no parsing or conversion is involved. The whole task is choosing the order of the checks.

    Step by step

    1. Check 400. The remainder operator % gives what is left after division, and a remainder of 0 means the number divides evenly. If year % 400 == 0, return true.
    2. Check 100. If year % 100 == 0, return false. A year that reaches this line is a century that failed the 400 test, like 1900.
    3. Check 4. If year % 4 == 0, return true. Only non-century years get here, and for them divisibility by 4 is the whole rule.
    4. Return false at the end. The year isn't divisible by 4, so it isn't a leap year.

    The solution in Rust

    impl Solution {
        fn is_leap_year(year: i32) -> bool {
            if year % 400 == 0 {
                return true;
            }
            if year % 100 == 0 {
                return false;
            }
            if year % 4 == 0 {
                return true;
            }
            return false;
        }
    }
    

    Rust details worth knowing:

    • No parentheses, required braces. The condition after if needs no parentheses, and the body must be in braces even for a single statement.
    • The condition must be a bool. Rust doesn't treat a number as true or false, so writing if year % 4 { ... } is a compile error. Compare explicitly with == 0.
    • No else needed. Every if body ends in a return, so the following lines only run when the condition was false.
    • % follows the dividend's sign. For negative years, -4 % 4 is still 0, and a remainder that isn't zero can be negative, for example -3 % 4 is -1. Comparing to 0 is safe either way.
    • Return type. -> bool means each return must be true or false, never a number.
    • Expression form. The whole function can also be one final expression with no return: year % 400 == 0 || (year % 4 == 0 && year % 100 != 0).

    Edge cases and common mistakes

    The two layers of the rule exist because a solar year is slightly shorter than 365.25 days. Dividing by 4 alone overcorrects, so century years are skipped, except every fourth century, which are kept. Years such as 1600, 2000 and 2400 are leap years, and 1700, 1800, 1900 and 2100 are not.

    • Checking 4 first. If the first test is year % 4 == 0 returning true, then 1900 is wrongly accepted, since 1900 divides by 4.
    • Checking 100 before 400. That rejects 2000, which is a leap year.
    • Using = instead of ==. A single = is assignment, and Rust rejects it in place of a comparison.
    • Mixing up the divisors. 1900 and 2100 are not leap years. 1600 and 2000 are.
    • Year 0. 0 % 400 is 0, so the function returns true. Whether year 0 exists depends on the calendar, but the arithmetic rule gives true.

    Testing

    • year = 2020 gives true.
    • year = 2021 gives false.
    • year = 1968 gives true.
    • year = 1900 gives false.
    • year = 2000 gives true.
    • year = 2100 gives false.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free