はじめに
プログラムを書く人は何十回と触れたことがあるであろう、うるう年の計算について。うるう年になる条件とコードに触れつつ、簡単に解決できる方法(Year.isLeap)を取り上げます。
開発環境
- Windows10
- Java11
うるう年の考え方
まず、うるう年の条件を確認します。条件は以下の通りです。
- 4で割り切れる年
- 100で割り切れない年
- 400で割り切れる年
4で割り切れる年であることがまず前提となります。その上で、例外として「100で割り切れる年はうるう年ではない」というのと、「(100で割り切れるけど)400で割り切れる年はうるう年である」という条件があります。
解決方法のコードサンプル
解決方法として以下のコードサンプルを用意してます。
- 前述の条件を満たすメソッドを作る
- YearクラスのisLeapメソッドを使う
さほど条件も多くないので自作も容易ですが、Java8以降のバージョンをお使いならYearクラスのisLeapメソッドを使うのが楽ではないかな、と思います。
メソッドを作る場合
isLeapメソッドを作ってうるう年判定を行います。
ソースコード
class LeapSample {
private static boolean isLeap(final int year) {
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
}
public static void main(String[] args) {
final int leapYear1 = 2024;
final int leapYear2 = 2000;
final int notLeapYear1 = 2100;
final int notLeapYear2 = 2022;
System.out.println("leapYear1(" + leapYear1 + ") is : " + isLeap(leapYear1));
System.out.println("leapYear2(" + leapYear2 + ") is : " + isLeap(leapYear2));
System.out.println("notLeapYear1(" + notLeapYear1 + ") is : " + isLeap(notLeapYear1));
System.out.println("notLeapYear2(" + notLeapYear2 + ") is : " + isLeap(notLeapYear2));
}
}
自作メソッド(isLeap)の解説
3行目の解説になります。
- 400は4の倍数でもあり、例外的な扱いをされているので、まず最初に確認しています。400で割り切れる場合はtrueを返してしまいます。
- 400の倍数では無い場合、4で割り切れて且つ100で割り切れない数か確認して結果を返します。
やっていることはこれだけです。コード量は多くないですね。
プログラム実行結果
leapYear1(2024) is : true
leapYear2(2000) is : true
notLeapYear1(2100) is : false
notLeapYear2(2022) is : false
Year.isLeapを使う
Yearクラスで実装されているisLeapメソッドを使った例です。
ソースコード
import java.time.Year;
class LeapSample2 {
public static void main(String[] args) {
final int leapYear1 = 2024;
final int leapYear2 = 2000;
final int notLeapYear1 = 2100;
final int notLeapYear2 = 2022;
System.out.println("leapYear1(" + leapYear1 + ") is : " + Year.isLeap(leapYear1));
System.out.println("leapYear2(" + leapYear2 + ") is : " + Year.isLeap(leapYear2));
System.out.println("notLeapYear1(" + notLeapYear1 + ") is : " + Year.isLeap(notLeapYear1));
System.out.println("notLeapYear2(" + notLeapYear2 + ") is : " + Year.isLeap(notLeapYear2));
}
}
プログラム解説
9行目から16行目までで実施しているprintlnメソッドの中で、Year.isLeap()を実行してうるう年かどうかを判定しています。
プログラム実行結果
leapYear1(2024) is : true
leapYear2(2000) is : true
notLeapYear1(2100) is : false
notLeapYear2(2022) is : false
自作メソッドと結果は変わりません。(自作メソッドが正しく作れている証明になりますね笑)
Year.isLeap()の実装
これはおまけですが、Eclipseを使って標準ライブラリのソースコードが参照できるので、Year.isLeapメソッドの実装を覗いてみました。
コード
public static boolean isLeap(long year) {
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
}
おお、ビット演算使ってる。
コードの解説
- 4で割り切れるかを計算するために、引数yearと3の論理積を取ります。(& は ビット演算子)
- 1の条件に一致したら、100で割り切れないか、400で割り切れるかの結果を返します。
まず4で割り切れる数値かどうかをチェックしてるんですね。その後、例外ケースにマッチするかを確認するロジックになってます。
論理積計算の例
基本情報技術者試験の記事ではないのでしっかりと書く気は無いですが、2000年を引数に取った場合の計算例です。(筆算形式で書いてます)
(2000) 0111 1101 0000
( 3) & 0000 0000 0011
------------------------
0000 0000 0000
&演算子を使って計算する場合、2000と3はそれぞれ2進数で考え、各桁の0・1のAND(論理積)を求めます。(1 と 1の場合:1、それ以外:0)
2000と3の場合、1どうしの組み合わせがないので、結果は0000 0000 0000 => 0となります。
最後に
YearクラスはJava8から導入されたクラスです。なので、歴史を積み重ねたシステムに携わっている方などは、そのシステム独自でうるう年を計算するロジックが共通関数としてありそうなので、知らない人もいるかもしれませんね。
楽して書けるものはどんどん使っていきたいものです。
コメント