Javaでカレンダーを作りたいけれど、曜日の整列や祝日の扱いでつまずいていませんか?
この記事では、Java標準のLocalDateを使ってカレンダーを作る3ステップを解説します。
「指定月のカレンダー表示」「曜日に合わせた整列」「日本の祝日を赤色で表示」を、コピペで動くサンプルコード付きで紹介します。
旧来のCalendarクラスとLocalDateの違いにも触れるため、どちらを使うべきか迷っている方もすっきり判断できます。
Javaカレンダーの設計を考える
カレンダーを作るにあたって、まずはどのような設計にするか考えます。
曜日を取得"] B --> C["月の最終日を取得"] C --> D["1日から最終日まで
ループ処理"] D --> E{"曜日に合わせて
空欄を挿入"} E --> F["日付を出力"] F --> G{"祝日判定"} G -->|"祝日"| H["赤色で表示"] G -->|"平日"| I["通常色で表示"] H --> J{"月末まで
続ける?"} I --> J J -->|"Yes"| D J -->|"No"| K["カレンダー完成"]
必要な機能
今回作成するカレンダーの仕様を考えます。
3つの機能を考慮して、以下のような出力を目指します。
2024年3月のカレンダー
日 月 火 水 木 金 土
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Javaでカレンダーを作成する2つの方法
Javaでカレンダーを作成する方法はいくつかありますが、標準ライブラリを使う方法が最も簡単です。
Calendarクラスを使う
Javaには Calendarクラスが用意されており、このクラスを使えば簡単に日付情報を取得できます。
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance(); // カレンダーインスタンスを生成
int year = calendar.get(Calendar.YEAR); // 年を取得
int month = calendar.get(Calendar.MONTH) + 1; // 月を取得、月は0はじまり
int day = calendar.get(Calendar.DAY_OF_MONTH); // 日を取得
System.out.println("今日の日付: " + year + "年" + month + "月" + day + "日");
}
}
出力
今日の日付: 2026年9月2日上のコードを実行すると、今日の日付が出力されます。なお、Calendar.MONTHは0始まり(1月=0)なので、表示する際は+1が必要です。
LocalDateを使う
LocalDateクラスを使うパターンです。
LocalDateとは、Java 8で導入された日付専用のクラスで、年・月・日を1始まりで扱い、一度作成すると値が変わらないイミュータブルな設計になっています。
import java.time.LocalDate;
public class LocalDateExample {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
System.out.println("今日の日付: " + date);
}
}
出力
今日の日付: 2026-09-02LocalDateの方がコードが短く、月の0始まりを気にする必要もないため使いやすいです。
CalendarクラスとLocalDateの違い
どちらを使うか迷ったら、以下の比較表を参考にしてください。
| 項目 | Calendarクラス | LocalDate |
|---|---|---|
| 導入バージョン | Java 1.1 | Java 8 |
| 月の扱い | 0始まり(1月=0) | 1始まり(1月=1) |
| 可変性 | ミュータブル(値が変わる) | イミュータブル(値が変わらない) |
| スレッドセーフ | 非スレッドセーフ | スレッドセーフ |
| 推奨度 | レガシー(非推奨) | 公式推奨 |
新規コードではLocalDateを使うのが推奨です。
Calendarクラスは月が0始まりでバグの温床になりやすく、ミュータブルなため意図しない値変更が起こりえます。
2026年9月時点の最新LTSはJava 25で、LocalDateはJava 8以降どのLTSでも標準で利用できます。
この記事でも、カレンダー表示の実装にはLocalDateを使います。
ただし、既存のレガシーコードがCalendarを使っている場合は、Calendar.toInstant()経由でLocalDateに変換できます。
新規部分だけLocalDateで書き、変換メソッドで橋渡しするのが現実的な移行方法です。
補足すると、LocalDateは値ベースでequals・hashCodeが実装されています。
そのため本記事のようにMap<LocalDate, String>のキーとして安全に使えます。
古いDateクラスは可変であるため、HashMapのキーに使うとキー登録後に状態が変わって検索できなくなる事故が起きやすい傾向があります。
この点でもLocalDateのほうが扱いやすいクラスです。
Javaでカレンダーを実装する
実際にカレンダーを表示するプログラムを作成します。
LocalDateでカレンダーを作成する手順
LocalDateを使って、指定した年・月のカレンダーを表示するプログラムを作ります。
Calendarクラスでも同様の処理は可能ですが、月が0始まりでバグを埋め込みやすいため、ここではLocalDateを採用しています。
import java.time.LocalDate;
import java.time.DayOfWeek;
import java.util.Scanner;
public class CalendarApp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// ユーザー入力
System.out.print("年を入力してください: ");
int year = scanner.nextInt();
System.out.print("月を入力してください: ");
int month = scanner.nextInt();
// 指定した年・月のカレンダーを表示
printCalendar(year, month);
scanner.close();
}
public static void printCalendar(int year, int month) {
LocalDate firstDay = LocalDate.of(year, month, 1);
int lastDay = firstDay.lengthOfMonth(); // その月の最終日
DayOfWeek startDay = firstDay.getDayOfWeek();
System.out.println(year + "年" + month + "月のカレンダー");
System.out.println("日 月 火 水 木 金 土");
// 月初めの曜日に合わせて空白を出力
int dayOfWeekValue = startDay.getValue() % 7; // Javaでは月曜=1, 日曜=7
for (int i = 0; i < dayOfWeekValue; i++) {
System.out.print(" ");
}
// 日付を出力
for (int day = 1; day <= lastDay; day++) {
System.out.printf("%2d ", day);
if ((day + dayOfWeekValue) % 7 == 0) { // 土曜日で改行
System.out.println();
}
}
System.out.println();
}
}カレンダーの実行結果を確認する
CalendarAppを実行すると、任意の年・月のカレンダーが表示されます。
年を入力してください: 2024
月を入力してください: 3
2024年3月のカレンダー
日 月 火 水 木 金 土
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
日付が正しく並ぶカレンダーが完成しました。
よくあるエラーと対処法
カレンダー実装でつまずきやすいポイントを3つ紹介します。
Calendar.MONTHが0始まり:Calendarクラスでは1月が0、12月が11です。表示時に+1を忘れると月がずれます。LocalDateなら1始まりなのでこの問題は起きません。DayOfWeek.getValue()の戻り値:LocalDateのgetDayOfWeek().getValue()は月曜=1、日曜=7を返します。日曜始まりのカレンダーにするには% 7で変換が必要です。- 存在しない日付の指定:
LocalDate.of(2024, 13, 1)のように範囲外の月を指定するとDateTimeExceptionが発生します。ユーザー入力を受け取る場合はバリデーションを入れましょう。
祝日を考慮したカレンダーを作成する
カレンダーに祝日を表示できるようにすると、より実用的なものになります。
日本の祝日は毎年変わるものもあるため、固定祝日と可変祝日(毎年日付が変わる祝日、成人の日など)に対応する必要があります。
日本の祝日を考慮する方法
日本の祝日をカレンダーに追加する方法はいくつかあります。
今回は固定祝日と可変祝日を組み合わせた方法でカレンダーを拡張します。
ただし本番運用まで見据えるなら話は変わります。
この記事のようなMapによる自前実装は学習用途としては最適ですが、春分の日・秋分の日の正確な算出や毎年の祝日改正への追従までは面倒を見きれません。
実務では祝日計算ライブラリ(jollydayなど)を使うか、内閣府が公開している祝日CSVを毎年インポートする方式のほうが保守性は高くなります。
祝日を定義する
まず、固定祝日をMapで管理し、可変祝日は計算します。
import java.time.LocalDate;
import java.time.DayOfWeek;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class HolidayCalendar {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// ユーザー入力
System.out.print("年を入力してください: ");
int year = scanner.nextInt();
System.out.print("月を入力してください: ");
int month = scanner.nextInt();
// カレンダーを表示
printCalendarWithHolidays(year, month);
scanner.close();
}
public static void printCalendarWithHolidays(int year, int month) {
LocalDate firstDay = LocalDate.of(year, month, 1);
int lastDay = firstDay.lengthOfMonth();
DayOfWeek startDay = firstDay.getDayOfWeek();
// 祝日マップを取得
Map<LocalDate, String> holidays = getHolidays(year);
System.out.println(year + "年" + month + "月のカレンダー");
System.out.println("日 月 火 水 木 金 土");
// 月初めの曜日に合わせて空白を出力
int dayOfWeekValue = startDay.getValue() % 7; // Javaでは月曜=1, 日曜=7
for (int i = 0; i < dayOfWeekValue; i++) {
System.out.print(" ");
}
// 日付を出力
for (int day = 1; day <= lastDay; day++) {
LocalDate date = LocalDate.of(year, month, day);
if (holidays.containsKey(date)) {
System.out.printf("\u001B[31m%2d\u001B[0m ", day); // 祝日は赤色表示
} else {
System.out.printf("%2d ", day);
}
if ((day + dayOfWeekValue) % 7 == 0) { // 土曜日で改行
System.out.println();
}
}
System.out.println();
}
public static Map<LocalDate, String> getHolidays(int year) {
Map<LocalDate, String> holidays = new HashMap<>();
// 固定祝日
holidays.put(LocalDate.of(year, 1, 1), "元日");
holidays.put(LocalDate.of(year, 2, 11), "建国記念の日");
holidays.put(LocalDate.of(year, 4, 29), "昭和の日");
holidays.put(LocalDate.of(year, 5, 3), "憲法記念日");
holidays.put(LocalDate.of(year, 5, 4), "みどりの日");
holidays.put(LocalDate.of(year, 5, 5), "こどもの日");
holidays.put(LocalDate.of(year, 11, 3), "文化の日");
holidays.put(LocalDate.of(year, 11, 23), "勤労感謝の日");
// 可変祝日(第○月曜日系)
holidays.put(getNthWeekdayOfMonth(year, 1, DayOfWeek.MONDAY, 2), "成人の日");
holidays.put(getNthWeekdayOfMonth(year, 7, DayOfWeek.MONDAY, 3), "海の日");
holidays.put(getNthWeekdayOfMonth(year, 9, DayOfWeek.MONDAY, 3), "敬老の日");
holidays.put(getNthWeekdayOfMonth(year, 10, DayOfWeek.MONDAY, 2), "スポーツの日");
return holidays;
}
public static LocalDate getNthWeekdayOfMonth(int year, int month, DayOfWeek weekday, int nth) {
LocalDate date = LocalDate.of(year, month, 1);
int count = 0;
while (date.getMonthValue() == month) {
if (date.getDayOfWeek() == weekday) {
count++;
if (count == nth) {
return date;
}
}
date = date.plusDays(1);
}
return null;
}
}祝日が赤色で表示されるようになりました。コードのポイントを解説します。
祝日カレンダーのコード解説
getHolidays()メソッドでは、元日や建国記念の日など毎年同じ日付の固定祝日をMapに登録しています。
可変祝日(成人の日、海の日など)はgetNthWeekdayOfMonth()で計算します。
getNthWeekdayOfMonth()は「第N週目の特定曜日」を求めるメソッドです。
月の1日から順に曜日をチェックし、指定した曜日がN回目に出現した日付を返します。例えば「1月の第2月曜日」で成人の日を算出します。
赤色表示には\u001B[31mというANSIエスケープシーケンス(ターミナルで文字に色を付ける特殊コード)を使っています。
\u001B[0mで元の色に戻します。
なお、上のサンプルコードには天皇誕生日(2月23日)・山の日(8月11日)・春分の日・秋分の日が含まれていません。
実用する場合はこれらの祝日もgetHolidays()メソッドに追加してください。
春分の日と秋分の日は年によって日付が変わるため、国立天文台の暦要項を参照して計算する必要があります。
また、祝日が日曜日と重なった場合の振替休日にも対応が必要です。
振替休日のロジックは「祝日の翌日が祝日でなければその日が振替休日」というルールで実装できます。
public static void addSubstituteHolidays(Map<LocalDate, String> holidays) {
// 元のMapのコピーに対して走査しないと、走査中に追加した振替休日が
// 再び振替休日の対象になってしまうため、キーのコピーを先に取得する
for (LocalDate date : new ArrayList<>(holidays.keySet())) {
if (date.getDayOfWeek() == DayOfWeek.SUNDAY) {
LocalDate substitute = date.plusDays(1);
while (holidays.containsKey(substitute)) {
substitute = substitute.plusDays(1);
}
holidays.put(substitute, "振替休日");
}
}
}祝日が日曜日と重なっていたら、祝日でなくなるまで1日ずつ後ろにずらして振替休日を登録します。
getHolidays()で祝日Mapを作成した後にこの処理を呼び出せば、振替休日も赤色表示の対象になります。
よくある質問
Q1. JavaでカレンダーはCalendarとLocalDateどちらで作るべきですか?
A1. 新規コードではLocalDateがおすすめです。月が1始まりでバグを起こしにくく、イミュータブルでスレッドセーフという利点があります。Calendarはレガシーな既存コードとの互換性が必要な場合のみ使うのが現実的です。
Q2. Javaで月初めの曜日を取得するにはどうすればいいですか?
A2. LocalDate.of(year, month, 1)で月初めの日付を作成し、getDayOfWeek()メソッドを呼び出します。戻り値のDayOfWeekはgetValue()で数値(月曜=1〜日曜=7)に変換できます。
Q3. 日本の祝日をJavaでどう管理すればいいですか?
A3. 元日など毎年同じ日付の固定祝日はMap<LocalDate, String>に登録し、成人の日など「第N月曜日」型の可変祝日は計算メソッドで算出するのが基本です。本番運用では祝日計算ライブラリの利用も検討してください。
Q4. LocalDateはMapのキーとして安全に使えますか?
A4. はい、安全に使えます。LocalDateは値ベースでequals・hashCodeが実装されているため、同じ年月日を表すインスタンスはMapのキーとして正しく一致します。可変な古いDateクラスとは対照的です。
Q5. 振替休日はどうやって実装しますか?
A5. 「祝日の翌日が祝日でなければその日が振替休日」というルールで実装します。祝日Mapを走査し、日曜日と重なる祝日があれば、祝日でなくなるまで1日ずつ後ろにずらして振替休日として登録します。
まとめ:Javaでカレンダーを作る方法
Javaの標準ライブラリだけで、祝日付きカレンダーを作成しました。シンプルな実装から祝日表示の応用まで、段階的に学べる構成になっています。
【要点まとめ】
- JavaではCalendarやLocalDateで日付操作が可能
- カレンダーの基礎は年と月の入力から始める
- 月初めの曜日取得で整ったカレンダー表示ができる
- 日付は改行処理により見やすく整列させる
- LocalDateのlengthOfMonthで月末日を取得する
- 固定祝日はMapに登録して管理できる
- 第○月曜日型の祝日は計算式で算出可能
- 祝日は赤色出力で視認性を向上させる
- Java標準ライブラリだけで実用的なカレンダーが作成可能
カレンダーが作れたら、次は数当てゲームやTodoリストアプリなど、少し複雑なプログラムに挑戦してみてください。






