【Java】うるう年を正確に判定する方法まとめ!初心者向けサンプル付きで徹底解説

お疲れ様です。はるさらと申します。
今回は、システム開発で意外と重要な
「うるう年」の判定について解説していきます。

カレンダー機能や年齢計算など、
日付を扱うシステムを作る際に、「うるう年」を正確に判定できないと、
日付が1日ずれてしまい、大きなバグにつながってしまいます。

この記事では、Javaでうるう年を正確かつシンプルに判定する方法を、
初心者向けのサンプルコード付きで、わかりやすく解説していきます。

この記事を最後まで読めば、うるう年の判定ロジックをバッチリ理解し、
自信を持って日付を扱うJavaプログラムを書けるようになっていきます。


Javaでうるう年を判定する基本的な方法

うるう年を判定するもっともシンプルで確実な方法は、
Java 8以降で導入されたjava.time.Yearクラスを使うことです。

このクラスには、isLeap()メソッドが用意されており
これを使用することが簡単かと思われます。

java.time.Year.isLeap()を使った基本例

Java 8より前のバージョンでは自力で計算ロジックを書く必要がありましたが、
現在はこのメソッドを使用するのがおすすめです。

サンプルコード(基本例)

import java.time.Year;
import java.util.Scanner;

public class LeapYearCheckerBasic {
    public static void main(String[] args) {
        // キーボードから年を入力
        Scanner scanner = new Scanner(System.in);
        System.out.print("判定したい年を入力してください(例: 2024): ");
        int yearInput = scanner.nextInt();
        scanner.close();

        // (1) YearクラスのofメソッドでYearオブジェクトを作成
        Year year = Year.of(yearInput);

        // (2) isLeap()メソッドでうるう年を判定
        boolean isLeap = year.isLeap(); 

        // 結果を出力
        if (isLeap) {
            System.out.println(yearInput + "年は、うるう年です。");
        } else {
            System.out.println(yearInput + "年は、うるう年ではありません。");
        }
    }
}

実行結果(例1:うるう年)

判定したい年を入力してください(例: 2024): 2024
2024年は、うるう年です。

実行結果(例2:平年)

判定したい年を入力してください(例: 2024): 2023
2023年は、うるう年ではありません。

コードの解説

  • (1) Year.of(yearInput):
    java.time.Yearクラスの静的メソッドであるof()を使って、
    入力された年(int型)からYearオブジェクトを作成しています。
    java.timeパッケージ(新しい日付と時刻API)は、
    従来のjava.util.Datejava.util.Calendarよりも使いやすく、
    バグの少ない設計になっています。
  • (2) year.isLeap():
    作成したYearオブジェクトのインスタンスメソッドである
    isLeap()を呼び出すだけで、その年がうるう年かどうかをboolean型(trueまたはfalse)で返してくれます

なぜYear.isLeap()を使うべきなのか?

自力で計算ロジックを書くこともできますが、
実務でYear.isLeap()が推奨されるのには明確な理由があります。
それは、うるう年の判定ルールが意外と複雑だからです。

うるう年判定のルールをおさらい

うるう年と判定されるのは、以下の3つの条件をすべて満たす年です。

  • 4で割り切れる
  • ただし、100で割り切れる年は除く
  • ただし、400で割り切れる年は含める

例として、このルールを具体的に見てみましょう。

4で割り切れる?100で割り切れる?400で割り切れる?うるう年?理由
2024YesNoNoYes4で割り切れる(条件1のみ)
2000YesYesYesYes400で割り切れるため(条件3)
1900YesYesNoNo100で割り切れるため(条件2)
2023NoNoNoNo4で割り切れない

この3つの条件をプログラミングで正確に表現するのは、
地味に面倒で、ちょっとしたミスでバグにつながりやすいんです。

実務での利用例:Date/Time APIの恩恵

実務では、単にうるう年を判定するだけでなく、
その判定結果を使って日付の妥当性チェックを行うことが多いです。

例えば、「2月29日」という日付が正しいかチェックする場合、
その年がうるう年でなければ「2月29日」は存在しない日付となります。

サンプルコード(実務利用例)

この例では、Yearクラスだけでなく、java.time.LocalDateクラスを組み合わせて、
特定の日付がうるう年でのみ有効かをチェックしています。

import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.DateTimeException;

public class LeapYearPracticalExample {
    public static void main(String[] args) {
        int yearToCheck = 2024; // うるう年
        int invalidYear = 2023; // 平年
        
        // 2024年(うるう年)の2月29日の妥当性チェック
        try {
            LocalDate feb29Leap = LocalDate.of(yearToCheck, Month.FEBRUARY, 29);
            
            // LocalDateのisLeap()は「そのLocalDateが属する年」がうるう年かを返します
            if (feb29Leap.isLeap()) {
                System.out.println(yearToCheck + "年はうるう年なので、" + feb29Leap + "は有効です。");
            }
        } catch (DateTimeException e) {
            // 2024年は有効なのでここは実行されない
        }
        
        // 2023年(平年)の2月29日の妥当性チェック
        Year year2023 = Year.of(invalidYear);

        if (!year2023.isLeapYear()) {
            System.out.println(invalidYear + "年はうるう年ではありません。");
            
            // 2月29日が存在するかをチェック
            try {
                // of(年, 月, 日)で存在しない日付を指定するとDateTimeExceptionが発生
                LocalDate invalidDate = LocalDate.of(invalidYear, Month.FEBRUARY, 29); 
            } catch (DateTimeException e) {
                System.out.println(invalidYear + "年の2月29日は存在しないため、日付としては無効です。");
            }
        }
    }
}

実行結果

2024年はうるう年なので、2024-02-29は有効です。
2023年はうるう年ではありません。
2023年の2月29日は存在しないため、日付としては無効です。

コードの解説

  • LocalDate.of(年, 月, 日)
    java.time.LocalDateは、年・月・日の情報を持つ日付を表すクラスです。
    存在しない日付(例:平年の2月29日)を作成しようとすると、
    DateTimeExceptionという例外を投げる仕様になっています。
  • try-catch (DateTimeException e)
    ・この例外をキャッチすることで、日付の妥当性チェックが簡単に、かつ確実に行えます。
    java.time APIのクラスを使うことで、
    日付の計算やチェックの際のバグを劇的に減らすこと可能です。

代替手法:自力で計算ロジックを実装する場合

ほとんどの場合、Year.isLeap()を使うべきですが、
古いJavaバージョン(Java 7以前)に対応する必要がある
あるいは純粋に学習目的で、自力でロジックを実装する方法も知っておくと役立ちます。

このロジックは、前述の「うるう年判定のルール」を
論理演算子(&&||!=剰余演算子(%)を使って表現するだけです。

判定ロジックを自作する関数

数学的な表現をそのままJavaコードに落とし込みます。

サンプルコード(代替手法比較)

import java.util.Scanner;

public class LeapYearCustomChecker {

    // (1) 自力で判定ロジックを実装したメソッド
    public static boolean isLeapYearCustom(int year) {
        // (4で割り切れる) AND ((100で割り切れない) OR (400で割り切れる))
        return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
    }

    // (2) Date/Time APIを使った判定メソッド(比較用)
    public static boolean isLeapYearAPI(int year) {
        return java.time.Year.of(year).isLeap();
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("判定したい年を入力してください(例: 1900, 2000, 2024): ");
        int yearInput = scanner.nextInt();
        scanner.close();

        // 比較
        boolean customResult = isLeapYearCustom(yearInput);
        boolean apiResult = isLeapYearAPI(yearInput);

        System.out.println("--- 判定結果 ---");
        System.out.println("自作ロジックでの判定: " + (customResult ? "うるう年です" : "平年です"));
        System.out.println("APIでの判定:      " + (apiResult ? "うるう年です" : "平年です"));

        if (customResult == apiResult) {
            System.out.println("結果は一致しました。");
        } else {
             System.out.println("結果が不一致です!ロジックを確認してください。");
        }
    }
}

実行結果(例1:400で割り切れる年)

判定したい年を入力してください(例: 1900, 2000, 2024): 2000
--- 判定結果 ---
自作ロジックでの判定: うるう年です
APIでの判定:      うるう年です
結果は一致しました。

実行結果(例2:100で割り切れるが400で割り切れない年)

判定したい年を入力してください(例: 1900, 2000, 2024): 1900
--- 判定結果 ---
自作ロジックでの判定: 平年です
APIでの判定:      平年です
結果は一致しました。

コードの解説と注意点

  • (1) (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))
    ・これが、うるう年判定の肝となる論理式です。
    %(剰余演算子)を使って、割り算のあまりを求めています。
    あまりが0なら「割り切れる」ということです。
  • (2) isLeapYearAPI(int year)
    こちらは、あくまで比較用としてYear.isLeap()を使っています。

間違えやすいポイント

自力でロジックを書くときに、特に間違えやすいのが以下の2点です。

  • 「100で割り切れる年は除く」の例外処理を忘れる:
    「4で割り切れる年=うるう年」と単純に考えてしまうと、
    1900年2100年などの「100の倍数だけど400の倍数ではない年」を
    誤ってうるう年と判定してしまいます。
  • 論理演算子のカッコの付け方を間違える:
    正しい論理の塊を、カッコなしで書いてしまうと、
    意図しない順番で計算されてしまい、誤判定の原因となります。

結論として、バグを避けるためにも、
特別な理由がない限りjava.time.Year.isLeap()を使うようにしましょう!


まとめ

今回は、Javaでうるう年を判定する確実な方法を、サンプル付きで解説しました。

  • Javaでうるう年を判定するもっとも簡単で確実な方法は、
    java.time.YearクラスのisLeap()メソッドを使うことです。
  • うるう年の判定ロジックは複雑で、自力で実装するとバグを生みやすいため、
    標準APIを使うのが推奨されます。
  • 古いJavaバージョンなどで自作ロジックが必要な場合は、
    論理式のカッコ()を正しく使って、正確な判定ロジックを記述することが重要です。

java.timeパッケージ(Java 8以降)は、
日付と時刻の処理をシンプルかつ確実にしてくれる非常に便利なツールです。

ぜひ、今回の内容を活かして、バグのない堅牢なJavaプログラム開発を進めてくださいね!

どなたかのお役に立てば幸いです。
それではまたー!