概要

「この日は休みかどうか」という判定は、営業日計算や納期管理、バッチスケジュールの制御など、業務システムのあちこちで必要になります。曜日だけなら DayOfWeek で済みますが、祝日が絡むと途端にやっかいになります。祝日データをどこから持ってくるか、振替休日をどう扱うか、会社独自の休業日をどう組み込むか――判定ロジック自体は単純でも、データの持ち方と組み合わせ方で実装の見通しが大きく変わります。この記事では、祝日セットを Set<LocalDate> で受け取り、曜日判定と合わせて「休日かどうか」を返す判定メソッドを Java 標準 API だけで実装します。record による祝日情報の構造化や、Java 21 の switch 式による曜日分岐も紹介します。

使いどころ

請求書の発行日が休日に当たった場合、前営業日に自動で繰り上げる判定ロジックに使う

バッチ処理の実行スケジュールで、休日をスキップするかどうかの分岐条件として利用する

勤怠管理システムで、出勤日が祝日に該当するかを判定し、休日出勤手当の対象かを振り分ける

コード例

HolidayChecker.java
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Set;

public class HolidayChecker {

    /** 指定日が祝日かどうかを判定する */
    public static boolean isHoliday(LocalDate date, Set<LocalDate> holidays) {
        return holidays.contains(date);
    }

    /** 指定日が休日(土曜・日曜・祝日)かどうかを判定する */
    public static boolean isNonWorkingDay(LocalDate date, Set<LocalDate> holidays) {
        DayOfWeek dow = date.getDayOfWeek();
        if (dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY) {
            return true;
        }
        return isHoliday(date, holidays);
    }

    /** 指定日が営業日かどうかを判定する */
    public static boolean isBusinessDay(LocalDate date, Set<LocalDate> holidays) {
        return !isNonWorkingDay(date, holidays);
    }

    public static void main(String[] args) {
        // 2024年の祝日(一部抜粋)
        var holidays = Set.of(
            LocalDate.of(2024, 1, 1),   // 元日
            LocalDate.of(2024, 1, 8),   // 成人の日
            LocalDate.of(2024, 2, 11),  // 建国記念の日
            LocalDate.of(2024, 2, 12),  // 振替休日
            LocalDate.of(2024, 5, 3),   // 憲法記念日
            LocalDate.of(2024, 5, 4),   // みどりの日
            LocalDate.of(2024, 5, 5),   // こどもの日
            LocalDate.of(2024, 5, 6)    // 振替休日
        );

        // 判定サンプル
        LocalDate newYear  = LocalDate.of(2024, 1, 1);  // 元日(祝日)
        LocalDate friday   = LocalDate.of(2024, 1, 5);  // 金曜日(平日)
        LocalDate saturday = LocalDate.of(2024, 1, 6);  // 土曜日

        System.out.println(newYear  + " 休日: " + isNonWorkingDay(newYear, holidays));  // true
        System.out.println(friday   + " 休日: " + isNonWorkingDay(friday, holidays));   // false
        System.out.println(saturday + " 休日: " + isNonWorkingDay(saturday, holidays)); // true

        // record で祝日名付きの情報を保持する例(Java 16+)
        record Holiday(LocalDate date, String name) {}
        var holiday = new Holiday(LocalDate.of(2024, 1, 1), "元日");
        System.out.println("祝日: " + holiday.date() + " " + holiday.name());
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

Set.of() で祝日データを不変セットとして簡潔に初期化できる。record で祝日名と日付のペアを表現すると可読性が上がる。

Java 17
// Java 17: Set.of() + record で簡潔に表現
var holidays = Set.of(
    LocalDate.of(2024, 1, 1),
    LocalDate.of(2024, 1, 8),
    LocalDate.of(2024, 2, 11)
);
record Holiday(LocalDate date, String name) {}

Library Comparison

標準 API(LocalDate + Set + DayOfWeek)祝日データを自前で管理し、曜日条件も自社ルールに合わせてカスタマイズしたいとき。依存ゼロで動作する。祝日データの年次更新や法改正への追従は自前で行う必要がある。
Jollyday各国の祝日データを外部ライブラリに委ねたいとき。初期導入は速い。日本の祝日は法改正への追従が遅れる場合がある。会社独自の休業日は結局自前で追加することになる。
内閣府 CSV + 自前パーサー正式な祝日データを外部から取得し、自前ロジックで判定したいとき。ネットワーク依存が生じるため、オフライン環境ではフォールバックが必要になる。

注意点

祝日セットに振替休日や国民の休日を含めるかどうかは、呼び出し側の責任になる。判定メソッドは渡された Set を信頼するだけなので、データが不完全だと結果も不正確になる

Set.of() は Java 9 以降でのみ使える。Java 8 環境では Collections.unmodifiableSet(new HashSet<>(Arrays.asList(...))) で代替する

土曜を営業日とする会社や、特定曜日が定休日の業種では、DayOfWeek の判定条件をカスタマイズする必要がある。ハードコードせず、除外曜日のセットを引数で受け取る設計が望ましい

祝日データは年ごとに更新が必要。特に春分・秋分は年によって日付が変わるため、固定値だけでは対応できない

FAQ

祝日と土曜が重なった場合、振替休日になりますか。

振替休日は「祝日が日曜に当たる場合」に翌営業日へ移動する制度です。土曜と祝日の重複では振替休日は発生しません。データ側で振替休日を含める運用が安全です。

会社独自の休業日(創立記念日など)はどう追加すればよいですか。

祝日セットに会社休業日を追加して渡すのが最も簡単です。判定メソッド側は Set の中身を区別しないため、データ側で一本化すれば追加のコード変更は不要です。

パフォーマンス上、祝日セットは毎回生成すべきですか。

年単位で不変なので、起動時やバッチ開始時に1回生成してキャッシュするのが一般的です。HashSet の contains は O(1) のため、セット自体のルックアップは高速です。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます