Java Tips | 日付・時間:営業日判定

Java Java
スポンサーリンク

営業日判定のゴールイメージ

「この日付は営業日か?」「締切日が休業日のときは翌営業日にずらしたい」
業務システムでは、こういう“営業日判定”が本当に頻繁に出てきます。

ここで大事なのは、
営業日=「土日以外」では終わらないことが多い、という現実です。
祝日・会社独自の休業日・年末年始など、現場ごとにルールが違います。

だからこそ、
「営業日判定のロジックを一か所に閉じ込める」
「曜日判定と祝日判定を分けて考える」
この二つを意識して設計するのが、とても重要になります。


最小構成:土日以外を営業日とみなす

DayOfWeek を使ったシンプルな営業日判定

まずは「土日以外は営業日」という、最小限のパターンから始めます。

import java.time.DayOfWeek;
import java.time.LocalDate;

public class SimpleBusinessDay {

    public static void main(String[] args) {
        LocalDate date1 = LocalDate.of(2025, 3, 28); // 金
        LocalDate date2 = LocalDate.of(2025, 3, 29); // 土

        System.out.println(date1 + " は営業日? " + isBusinessDay(date1)); // true
        System.out.println(date2 + " は営業日? " + isBusinessDay(date2)); // false
    }

    public static boolean isBusinessDay(LocalDate date) {
        DayOfWeek dow = date.getDayOfWeek();
        return dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY;
    }
}
Java

ここで一番大事なのは、
「営業日判定を isBusinessDay(LocalDate) というメソッドに閉じ込めた」ことです。

この一手間で、
「あとから祝日を考慮したくなった」「土曜も営業に変わった」
といった仕様変更に、かなり強くなります。


祝日・会社休業日を考慮した営業日判定

祝日リストを持たせて判定する

現実の業務では、「土日+祝日+会社独自の休業日」を休みとしたいことが多いです。
ここでは、簡単のために「祝日を LocalDate の集合として持つ」パターンを示します。

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

public class BusinessDayWithHolidays {

    private final Set<LocalDate> holidays = new HashSet<>();

    public BusinessDayWithHolidays(Set<LocalDate> holidays) {
        this.holidays.addAll(holidays);
    }

    public boolean isBusinessDay(LocalDate date) {
        DayOfWeek dow = date.getDayOfWeek();

        if (dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY) {
            return false;
        }
        if (holidays.contains(date)) {
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        Set<LocalDate> holidays = new HashSet<>();
        holidays.add(LocalDate.of(2025, 1, 1));  // 元日
        holidays.add(LocalDate.of(2025, 1, 2));  // 会社休業日
        holidays.add(LocalDate.of(2025, 1, 3));  // 会社休業日

        BusinessDayWithHolidays checker = new BusinessDayWithHolidays(holidays);

        LocalDate d1 = LocalDate.of(2025, 1, 1); // 祝日
        LocalDate d2 = LocalDate.of(2025, 1, 4); // 土曜
        LocalDate d3 = LocalDate.of(2025, 1, 6); // 月曜

        System.out.println(d1 + " 営業日? " + checker.isBusinessDay(d1)); // false
        System.out.println(d2 + " 営業日? " + checker.isBusinessDay(d2)); // false
        System.out.println(d3 + " 営業日? " + checker.isBusinessDay(d3)); // true
    }
}
Java

ここで深掘りしたいポイントは二つです。

一つ目は、
「曜日判定」と「祝日判定」を分けて書いていること。
これにより、「土曜も営業にしたい」「祝日は別マスタにしたい」といった変更がしやすくなります。

二つ目は、
「祝日情報を外から注入できるようにしている」こと。
コンストラクタで Set<LocalDate> を受け取るようにしておけば、
DB・設定ファイル・外部 API など、どこからでも祝日情報を持ってこられます。


営業日を使った「次の営業日」計算

営業日でない場合に、翌営業日にずらす

よくある要件に、
「締切日が休業日の場合は、翌営業日に繰り延べる」があります。

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

public class NextBusinessDayExample {

    public static void main(String[] args) {
        Set<LocalDate> holidays = Set.of(
                LocalDate.of(2025, 1, 1),
                LocalDate.of(2025, 1, 2),
                LocalDate.of(2025, 1, 3)
        );

        BusinessDayWithHolidays checker = new BusinessDayWithHolidays(holidays);

        LocalDate due = LocalDate.of(2025, 1, 4); // 土曜
        LocalDate nextBusiness = nextBusinessDay(due, checker);

        System.out.println("締切日       : " + due);          // 2025-01-04
        System.out.println("実際の締切日 : " + nextBusiness); // 2025-01-06
    }

    public static LocalDate nextBusinessDay(LocalDate date, BusinessDayWithHolidays checker) {
        LocalDate d = date;
        while (!checker.isBusinessDay(d)) {
            d = d.plusDays(1);
        }
        return d;
    }
}
Java

ここでの重要ポイントは、
「営業日判定ロジックを再利用して、“次の営業日”も表現している」ことです。

isBusinessDay を一か所に閉じ込めておけば、
「翌営業日」「前営業日」「N 営業日後」などのロジックも、
すべてその上に積み上げることができます。


N 営業日後を求める

「3 営業日後」などの計算

例えば「入金確認から 3 営業日後に発送する」といった要件です。

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

public class NBusinessDaysLaterExample {

    public static void main(String[] args) {
        Set<LocalDate> holidays = Set.of(
                LocalDate.of(2025, 1, 1),
                LocalDate.of(2025, 1, 2),
                LocalDate.of(2025, 1, 3)
        );

        BusinessDayWithHolidays checker = new BusinessDayWithHolidays(holidays);

        LocalDate base = LocalDate.of(2025, 1, 6); // 月曜
        LocalDate after3 = plusBusinessDays(base, 3, checker);

        System.out.println("基準日     : " + base);   // 2025-01-06
        System.out.println("3営業日後 : " + after3); // 2025-01-09
    }

    public static LocalDate plusBusinessDays(LocalDate base, int n, BusinessDayWithHolidays checker) {
        LocalDate d = base;
        int count = 0;
        while (count < n) {
            d = d.plusDays(1);
            if (checker.isBusinessDay(d)) {
                count++;
            }
        }
        return d;
    }
}
Java

ここで深掘りしたいのは、
「営業日という概念は“日数”ではなく“カレンダー+ルール”で決まる」という点です。

単純に plusDays(3) ではなく、
「1 日ずつ進めながら、営業日だけをカウントする」という発想が必要になります。


設計のコツ:営業日判定を“ドメインの中心”に置く

isBusinessDay(LocalDate) を“真ん中”に置く

営業日判定は、
締切日、発送日、入金日、バッチ実行日など、
システムのあらゆるところに顔を出します。

だからこそ、
「営業日かどうか」を判定するメソッドを、ドメインの中心に置く
という設計がとても効いてきます。

例えば、こんなインターフェースを切っておくイメージです。

public interface BusinessCalendar {
    boolean isBusinessDay(LocalDate date);
    LocalDate nextBusinessDay(LocalDate date);
    LocalDate previousBusinessDay(LocalDate date);
    LocalDate plusBusinessDays(LocalDate base, int n);
}
Java

実装クラスの中で、
曜日・祝日・会社休業日・特別営業日(祝日だけど営業する日)などをすべて吸収してしまえば、
業務ロジック側は「営業日」という概念だけを意識すればよくなります。


まとめ:営業日判定で絶対に覚えてほしいこと

営業日判定は、「カレンダー+会社ルール」をコードに落とし込む作業です。

曜日判定には DayOfWeek を使う。
祝日・会社休業日は Set<LocalDate> やマスタテーブルとして外出しする。
isBusinessDay(LocalDate) を一か所に閉じ込めて、そこを“真ん中”に据える。
「翌営業日」「N 営業日後」は、営業日判定を使って 1 日ずつ進めるイメージで実装する。

もしあなたのコードのどこかに、
「土日だけ if で除外している」「祝日判定が画面ごとにバラバラに書かれている」
といった箇所があれば、
そこを一度「営業日カレンダー」という一つのユーティリティに集約できないか眺めてみてください。

それができたとき、
あなたのシステムは“時間とカレンダーに強い”方向へ、ぐっと近づきます。

タイトルとURLをコピーしました