Start learning free

LESSON 85 OF 348 · CONDITIONAL STATEMENTS - CHALLENGES

Leap Year in Kotlin: Divisibility Checks with the % Operator

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:

leapYear(2020) ➞ true

leapYear(2021) ➞ false

leapYear(1968) ➞ true

leapYear(1900) ➞ false

Video Solution:

STEP 1 OF 4
    Ctrl + Enter to check

    KOTLIN · CONDITIONAL STATEMENTS - CHALLENGES

    Leap Year in Kotlin, explained

    Problem overview

    A leap year is a year with an extra day. The rule has two parts. A year is a leap year when it is divisible by 4. The exception is a century year, one divisible by 100 such as 1800 or 1900, which is a leap year only when it is also divisible by 400. The task is a function isLeapYear(year: Int): Boolean inside class Solution that returns true or false.

    Examples:

    • 2020 is divisible by 4 and is not a century year, so the answer is true.
    • 2021 is not divisible by 4, so the answer is false.
    • 1968 is divisible by 4, so the answer is true.
    • 1900 is divisible by 100 but not by 400, so the answer is false.

    Approach

    The rule has a main case and two exceptions, and they overlap: 2000 is divisible by 4, by 100 and by 400. If you test for 4 first, you answer true for 1900 too, which is wrong. The way out is to test from the most specific condition to the most general one and return as soon as one applies:

    1. Divisible by 400? Leap year.
    2. Divisible by 100 (and so not by 400)? Not a leap year.
    3. Divisible by 4 (and so not by 100)? Leap year.
    4. Anything else? Not a leap year.

    Each check can assume that the earlier ones failed. That is why the second test does not need to say "divisible by 100 but not 400".

    Step by step

    1. Check 400 first. The condition year % 400 == 0 uses the remainder operator: a remainder of 0 means the division is exact. Such a year is also divisible by 100 and by 4, so catching it first means a year like 2000 is accepted before the century rule can reject it.
    2. Reject other centuries. A year that reaches the check year % 100 == 0 was not divisible by 400, so it is a century year that is not a leap year, like 1900. Return false.
    3. Accept multiples of 4. Only non-century years get here, and for those, divisibility by 4 is the whole rule. 2020 and 1968 return true here.
    4. Return false at the end. A year such as 2021 passes none of the three checks.

    The solution in Kotlin

    class Solution {
        fun isLeapYear(year: Int): Boolean {
            if (year % 400 == 0) {
                return true
            }
            if (year % 100 == 0) {
                return false
            }
            if (year % 4 == 0) {
                return true
            }
            return false
        }
    }
    

    Kotlin details worth knowing:

    • The % operator. year % 4 is the remainder after dividing year by 4. For positive years it is between 0 and 3.
    • Each return ends the function. The code needs no else. A later check runs only when the earlier ones did not return.
    • Integer division and remainder. Both truncate toward zero, so a negative year gives a remainder that is zero or negative, never positive. Testing for == 0 works for any sign.
    • A shorter form. The function body can be reduced to one expression: return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0). It says the same thing, but the ordered checks are easier to follow and to extend.

    Which line decides each year

    yeardeciding lineresult
    2000year % 400 == 0true
    1900year % 100 == 0false
    2020year % 4 == 0true
    2021the final return falsefalse

    Every year reaches exactly one of the four return statements, and the order of the checks decides which one. If you move a check, run these four years again to see what changed.

    Edge cases and common mistakes

    • Checking 4 first. This returns true for 1900. Whenever a rule has exceptions to exceptions, test the most specific one first.
    • Forgetting 400. Without it, 2000 is rejected as an ordinary century year, but it is a leap year.
    • Using = instead of ==. In a condition, a single = is an assignment and Kotlin rejects it. Use == to compare.
    • Dividing instead of taking the remainder. year / 4 == 0 is true only for years from -3 to 3. Use % for divisibility tests.
    • Century years. 1800 and 1900 are not leap years, while 1600 and 2000 are.

    Why the calendar needs this rule

    A year lasts about 365.2425 days. Adding one day every fourth year is slightly too much, since it assumes 365.25 days. Dropping the day in century years corrects most of the excess, and keeping it in years divisible by 400 corrects the rest. Over 400 years the rule produces 97 leap years, which averages to exactly 365.2425 days per year. Knowing where the rule comes from also helps you remember the order of the three tests: the 400 exception sits on top of the 100 exception, and the 100 exception sits on top of the basic rule of 4.

    Testing

    • isLeapYear(2020) returns true.
    • isLeapYear(2021) returns false.
    • isLeapYear(1968) returns true.
    • isLeapYear(1900) returns false.
    • isLeapYear(2000) returns true.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free