「Javaでうるう年を判定するロジックはどう組めばいいのだろう?」
「もっと簡単な方法はないのかな?」
「うるう年判定で間違いやすいポイントがあれば知りたい」
プログラミングをしていると、日付の扱いは避けて通れない課題の一つです。
特に「うるう年」の判定は、単純なようでいて、意外な落とし穴があるものです。
私自身、過去に日付処理のバグで頭を悩ませた経験があり、うるう年のロジックについても深く学んだ経緯があります。
この記事では、Javaでうるう年を判定したいと考えている方に向けて、基本的な考え方からJavaの標準APIを利用した効率的な方法、そしてよくある間違いまで、網羅的に解説します。
この記事を読めば、Javaにおけるうるう年の判定方法をしっかりと理解し、自信を持って実装できるようになるでしょう。
そもそも「うるう年」とは?

Javaでのうるう年判定方法に触れる前に、まずは「うるう年」そのものについておさらいしましょう。
正確な定義を知ることは、正しいプログラムを書くための第一歩です。
うるう年とは、暦と地球の公転周期とのずれを調整するために設けられた年のことです。
地球が太陽の周りを1周するのにかかる時間は正確には365日ではなく、およそ365.2422日です。
この端数を調整しないと、暦と季節が少しずつずれていってしまいます。
このずれを補正するため、うるう年には2月が29日までとなり、1年が366日になります。うるう年のルールは以下の通りです。
例えば、2024年は4で割り切れるため、うるう年です。
1900年は4で割り切れ、かつ100でも割り切れるため平年となります。
一方、2000年は4で割り切れ、100でも割り切れ、さらに400でも割り切れるため、うるう年となるのです。
このルールを正確に把握することが、Javaでうるう年を判定する上で非常に重要です。
Javaでうるう年を判定する方法

うるう年のルールを理解したところで、次にJavaでこれらのルールに基づいてうるう年を判定する基本的な方法を見ていきましょう。
まずは、Javaの標準APIを使わずに、条件分岐だけで判定ロジックを実装する方法です。
if文だけで実装する方法(西暦を整数で判定)
うるう年の判定ロジックは、前述の3つのルールをif文で表現することで実装できます。
具体的には、与えられた西暦(整数)に対して、以下の条件を順に評価していきます。
public class LeapYearChecker {
public boolean isLeapYearByIf(int year) {
// 400で割り切れる年は必ずうるう年
if (year % 400 == 0) {
return true; // 400で割り切れる年はうるう年
}
// 400で割り切れないが100で割り切れる年は平年です。
if (year % 100 == 0) {
return false; // 100で割り切れる年は平年
}
// 100で割り切れず、4で割り切れる年はうるう年です。
if (year % 4 == 0) {
return true; // 4で割り切れる年はうるう年
}
// 上記のいずれにも当てはまらない場合は平年です。
return false; // それ以外は平年
}
public static void main(String[] args) {
LeapYearChecker checker = new LeapYearChecker();
int year1 = 2024;
int year2 = 1900;
int year3 = 2000;
int year4 = 2023;
System.out.println(year1 + "年はうるう年か? : " + checker.isLeapYearByIf(year1)); // true
System.out.println(year2 + "年はうるう年か? : " + checker.isLeapYearByIf(year2)); // false
System.out.println(year3 + "年はうるう年か? : " + checker.isLeapYearByIf(year3)); // true
System.out.println(year4 + "年はうるう年か? : " + checker.isLeapYearByIf(year4)); // false
}
}このコードでは、year % 400 == 0、year % 100 == 0、year % 4 == 0 という条件を順に評価しています。
剰余演算子 % を用いて、割り切れるかどうかを判定しているのがポイントです。
この順序で評価することで、うるう年のルールを正確に網羅できます。
この方法は、Javaの基本的な構文だけで実装できるため、学習の初期段階や、外部ライブラリに頼れない環境では有効な手段と言えるでしょう。
しかし、条件の順序や論理を間違えやすいため、テストを十分に行う必要があります。
うるう年をべた書きする方法
ごく稀なケースとして、判定対象となる年が極めて限定的で、かつ将来的に変更がないと断言できる場合、特定の年を直接コード内に記述する方法も考えられなくはありません。
例えば、特定の数年間だけのうるう年リストを事前に用意しておくようなイメージです。
import java.util.List;
public class LeapYearChecker {
private static final List<Integer> SPECIFIC_LEAP_YEARS = List.of(
2020,
2024,
2028);
public boolean isSpecificLeapYear(int year) {
return SPECIFIC_LEAP_YEARS.contains(year);
}
}この「年をべた書きする方法」は、推奨はされません。保守性や拡張性が著しく低いからです。
将来的に判定対象の年が増えたり、ロジックの修正が必要になったりした場合、コードの変更が非常に煩雑になります。
また、うるう年の普遍的なルールに基づいているわけではないため、汎用性もありません。
学習目的で様々なアプローチを考えることは良いですが、実務でこのような実装を選択する場面はほぼないと言えるでしょう。
Java標準APIでうるう年を判定する方法

Javaには、日付や時刻を扱うための便利な標準APIが用意されています。
これらのAPIを利用することで、より簡単かつ安全にうるう年を判定することが可能です。
特にJava 8以降で導入された java.time パッケージは、非常に強力で使いやすいAPIを提供しています。
java.time.Year クラスを使う
java.time.Year クラスの isLeap() メソッドを使用するのが最も簡単で推奨される方法です。
java.time.Year.isLeap(long year) メソッドは、Javaでうるう年を判定する最も現代的で簡潔な方法です。
このメソッドがうるう年の判定ロジックを内部に完全にカプセル化しており、開発者は複雑なルールを意識する必要がないからです。
また、java.time パッケージ自体がスレッドセーフで不変性を重視した設計になっているため、信頼性も高いと言えます。
import java.time.Year;
public class LeapYearChecker {
public boolean isLeapYearByJavaTime(int yearValue) {
// 指定された年を表すYearオブジェクトを取得します。
Year year = Year.of(yearValue);
// isLeap()メソッドでうるう年かどうかを判定します。
return year.isLeap();
}
public static void main(String[] args) {
LeapYearChecker checker = new LeapYearChecker();
int year1 = 2024;
int year2 = 1900;
int year3 = 2000;
int year4 = 2023;
System.out.println(year1 + "年はうるう年か? (java.time): " + checker.isLeapYearByJavaTime(year1)); // true
System.out.println(year2 + "年はうるう年か? (java.time): " + checker.isLeapYearByJavaTime(year2)); // false
System.out.println(year3 + "年はうるう年か? (java.time): " + checker.isLeapYearByJavaTime(year3)); // true
System.out.println(year4 + "年はうるう年か? (java.time): " + checker.isLeapYearByJavaTime(year4)); // false
}
}
このコードは非常にシンプルです。
Year.of(yearValue) で指定した年の Year オブジェクトを生成し、そのオブジェクトの isLeap() メソッドを呼び出すだけで、うるう年かどうかが boolean 値で返されます。
内部的には、うるう年の複雑な判定ルールが正しく実装されているため、開発者がロジックの誤りを心配する必要はありません。
java.time.Year クラスの利用を第一候補として検討すべきでしょう。
Calendar クラスを使う方法
Java 7以前の環境や、古いコードベースを扱っている場合には、java.util.Calendar クラス、具体的にはそのサブクラスである java.util.GregorianCalendar クラスの isLeapYear(int year) メソッドを利用する方法があります。
GregorianCalendar.isLeapYear(int year) メソッドは、古いJavaバージョンでも利用できる、信頼性の高い標準APIによるうるう年判定方法です。
このメソッドもJavaの標準ライブラリの一部として提供されており、うるう年の判定ロジックが組み込まれているため、自前でロジックを組むよりも安全かつ簡潔です。
java.time パッケージほど現代的ではありませんが、依然として有効な選択肢です。
import java.util.GregorianCalendar;
public class LeapYearChecker {
public boolean isLeapYearByCalendar(int year) {
// GregorianCalendarのインスタンスを生成する必要はありません。
// isLeapYearメソッドはstaticではありませんが、
// 通常はインスタンスメソッドとして使います。
// しかし、この場合は年を指定するだけなので、
// 一時的なインスタンスを作成して呼び出すか、
// より直接的なのは GregorianCalendar の仕様を基にしたものです。
// GregorianCalendarの仕様では、その年のカレンダーシステムでのうるう年を判定します。
GregorianCalendar gc = new GregorianCalendar();
return gc.isLeapYear(year);
}
public static void main(String[] args) {
LeapYearChecker checker = new LeapYearChecker();
int year1 = 2024;
int year2 = 1900;
int year3 = 2000;
int year4 = 2023;
System.out.println(year1 + "年はうるう年か? (Calendar): " + checker.isLeapYearByCalendar(year1)); // true
System.out.println(year2 + "年はうるう年か? (Calendar): " + checker.isLeapYearByCalendar(year2)); // false
System.out.println(year3 + "年はうるう年か? (Calendar): " + checker.isLeapYearByCalendar(year3)); // true
System.out.println(year4 + "年はうるう年か? (Calendar): " + checker.isLeapYearByCalendar(year4)); // false
}
}
GregorianCalendar クラスは、グレゴリオ暦(現在私たちが一般的に使用している暦)のルールに基づいています。
isLeapYear(int year) メソッドに西暦年を渡すことで、その年がうるう年かどうかを判定できます。
java.util.Calendar クラスは、java.time パッケージに比べるとAPI設計がやや古く、可変オブジェクトであるなどの扱いにくさもありますが、うるう年の判定という特定の目的においては十分に機能します。
よくある間違いと注意点

Javaでうるう年を判定する際には、いくつかの間違いやすいポイントや注意点があります。
これらを事前に把握しておくことで、バグの少ない堅牢なコードを書く助けになります。
100年ごと・400年ごとの例外条件の見落とし
うるう年判定で最もよくある間違いの一つは、単純に「4で割り切れる年がうるう年」とだけ記憶してしまい、100年ごとと400年ごとの例外ルールを見落としてしまうことです。
100で割り切れる年は平年、ただし400で割り切れる年はうるう年、という例外条件は自作ロジックにおいて致命的なバグの原因となります。
この例外を考慮しないと、例えば1900年を誤ってうるう年と判定したり、2000年を誤って平年と判定したりしてしまうからです。
ロジックを正しく組まないと、特定ケースでうるう年の判定に失敗します。
標準API(java.time.Year や GregorianCalendar)を使用する場合は、これらのルールがAPI内部に正しく実装されているため、開発者がこの間違いを犯す心配はありません。
うるう年判定に失敗しやすいパターン
うるう年の判定ロジックを自作した場合、特に失敗しやすいのは境界値となる年や、例外ルールが適用される年でのテストが不十分な場合です。
自作のうるう年判定ロジックは、例外ルールが適用される年(例: 1900年、2000年)やその近辺の年で徹底的にテストするべきです。
これらの年がルール変更の境界にあたり、ロジックの欠陥が露呈しやすいためです。
テストケースとして含めるべき代表的な年は以下の通りです。
これらのパターンで正しく判定できるかを確認することで、自作ロジックの信頼性を高められます。
繰り返しになりますが、Javaの標準APIを使用すれば、これらのテストはAPI提供者側で実施済みと期待できるため、開発者の負担は大幅に軽減されます。
まとめ:どの方法を選ぶべきか?
ここまで、Javaでうるう年を判定するいくつかの方法を見てきました。では、実際に開発する際にはどの方法を選ぶのが最適なのでしょうか。
APIを使うか、自作ロジックかの判断基準
ほとんどの場合、Javaの標準API(特に java.time.Year)を使用することが推奨されます。
- 信頼性: 標準APIは十分にテストされており、うるう年の複雑なルールを正確に処理します。自作ロジックで起こりがちなルールの見落としや実装ミスを防げます。
- 簡潔性: APIメソッドを呼び出すだけで判定できるため、コードが非常にシンプルになります。これにより、可読性やメンテナンス性が向上します。
- 効率性: 標準APIはパフォーマンス面でも最適化されていることが期待できます。
自作ロジックを検討するのは、以下のような非常に限定的な状況でしょう。
- Javaのバージョンが極端に古く、適切なAPIが利用できない場合(ただし、
GregorianCalendarはJava 1.1から存在します)。 - プログラミングの学習目的で、あえてアルゴリズムを自分で実装してみたい場合。
- 実行環境に極めて厳しい制約があり、標準ライブラリの利用すら制限されるような特殊なケース
基本的には、車輪の再発明を避け、実績のある標準APIに頼るのが賢明な判断です。
実務での使い所と注意点
実務でJavaを使ってうるう年を判定する必要がある場合、プロジェクトで使用しているJavaのバージョンに応じて最適なAPIを選択します。
- Java 8以降:
java.time.Year.isLeap()を使用しましょう。 - Java 7以前:
java.util.GregorianCalendar.isLeapYear(int year)を使用します。
うるう年のルールを正しく理解し、適切な方法を選択することで、バグのない安定したシステム開発に繋げてください。