C# Tips | 日付・時間処理:営業日判定

C# C#
スポンサーリンク

はじめに 「営業日判定」は“締切と期日のリアルさ”を決める心臓部

業務システムでよく出てくる「3営業日以内に対応」「翌営業日に処理」「営業日ベースで締切計算」。
ここでいう「営業日」が正しく判定できていないと、締切がズレたり、ユーザーとの約束を破ることになります。

C# では、まず「土日かどうか」を判定し、
必要に応じて「祝日カレンダー」を組み合わせることで、
実務レベルの営業日判定を実現できます。

ここでは、
土日判定 → 営業日判定の基本 → 祝日対応の考え方 → ユーティリティ化 → 応用(次の営業日を求める)
という流れで、初心者向けにかみ砕いて説明していきます。


ステップ1:まずは「土日かどうか」を判定する

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

営業日判定の一番の土台は「土日かどうか」です。
C# の DateTime には DayOfWeek プロパティがあり、ここから曜日を判定できます。

using System;

public static class BusinessDayUtil
{
    public static bool IsWeekend(DateTime date)
    {
        DayOfWeek w = date.DayOfWeek;
        return w == DayOfWeek.Saturday || w == DayOfWeek.Sunday;
    }

    public static bool IsWeekday(DateTime date)
    {
        return !IsWeekend(date);
    }
}
C#

使い方のイメージです。

DateTime d1 = new DateTime(2026, 2, 9);  // 月
DateTime d2 = new DateTime(2026, 2, 10); // 火
DateTime d3 = new DateTime(2026, 2, 14); // 土

Console.WriteLine(BusinessDayUtil.IsWeekday(d1)); // true
Console.WriteLine(BusinessDayUtil.IsWeekday(d2)); // true
Console.WriteLine(BusinessDayUtil.IsWeekday(d3)); // false
C#

ここでの重要ポイントは、
「土日判定を生の if 文であちこちに書かず、ユーティリティに閉じ込める」ことです。
これだけでも、コードの読みやすさと変更のしやすさがかなり変わります。


ステップ2:「営業日=平日かつ祝日ではない」という定義にする

営業日の定義をコードで表現する

多くの日本の業務システムでは、
「営業日=土日以外かつ祝日以外」という定義になります。

この定義をそのままコードに落とし込むと、こうなります。

public static class BusinessDayUtil
{
    public static bool IsWeekend(DateTime date)
    {
        DayOfWeek w = date.DayOfWeek;
        return w == DayOfWeek.Saturday || w == DayOfWeek.Sunday;
    }

    public static bool IsHoliday(DateTime date)
    {
        // ここは後で差し替え可能な“祝日判定”にする
        return false;
    }

    public static bool IsBusinessDay(DateTime date)
    {
        return !IsWeekend(date) && !IsHoliday(date);
    }
}
C#

ここで大事なのは、
「営業日判定の中心は IsBusinessDay に集約する」という設計です。

画面やロジック側では、

if (BusinessDayUtil.IsBusinessDay(date)) { ... }
C#

とだけ書けばよくなり、
「土日かどうか」「祝日かどうか」の詳細はユーティリティ側に隠せます。


ステップ3:祝日判定をどう設計するか

祝日ロジックは“差し替え可能”にしておく

祝日は、国や会社のルールによって変わりますし、
将来変わる可能性もあります。

そのため、祝日判定は
「別のコンポーネントに委譲できるようにしておく」
のが実務的です。

例えば、こんなインターフェースを用意します。

public interface IHolidayProvider
{
    bool IsHoliday(DateTime date);
}
C#

そして、BusinessDayUtil に注入できるようにします。

public static class BusinessDayUtil
{
    private static IHolidayProvider? _holidayProvider;

    public static void SetHolidayProvider(IHolidayProvider provider)
    {
        _holidayProvider = provider;
    }

    public static bool IsWeekend(DateTime date)
    {
        DayOfWeek w = date.DayOfWeek;
        return w == DayOfWeek.Saturday || w == DayOfWeek.Sunday;
    }

    public static bool IsHoliday(DateTime date)
    {
        if (_holidayProvider == null)
        {
            return false;
        }

        return _holidayProvider.IsHoliday(date);
    }

    public static bool IsBusinessDay(DateTime date)
    {
        return !IsWeekend(date) && !IsHoliday(date);
    }
}
C#

祝日データをどこから取るか(DB、設定ファイル、外部APIなど)は、
IHolidayProvider の実装側に任せる形です。

例えば「固定の祝日リストを持つ簡易版」はこう書けます。

using System;
using System.Collections.Generic;

public class FixedHolidayProvider : IHolidayProvider
{
    private readonly HashSet<DateOnly> _holidays;

    public FixedHolidayProvider(IEnumerable<DateOnly> holidays)
    {
        _holidays = new HashSet<DateOnly>(holidays);
    }

    public bool IsHoliday(DateTime date)
    {
        var d = DateOnly.FromDateTime(date);
        return _holidays.Contains(d);
    }
}
C#

初期化時にこう設定します。

var holidays = new[]
{
    new DateOnly(2026, 1, 1),
    new DateOnly(2026, 1, 13),
    // …必要なだけ追加
};

BusinessDayUtil.SetHolidayProvider(new FixedHolidayProvider(holidays));
C#

こうしておくと、
「祝日の定義を変えたい」「テスト用にダミーの祝日を使いたい」といったときに、
IHolidayProvider の実装を差し替えるだけで済みます。


ステップ4:営業日判定を使った“次の営業日”ユーティリティ

「翌営業日」を求める処理は超よく使う

営業日判定ができるようになると、
次に欲しくなるのが「翌営業日」「n営業日後」です。

まずは「翌営業日」を求めるメソッドを作ってみます。

public static class BusinessDayUtil
{
    // 既存のメソッドは省略(IsWeekend, IsHoliday, IsBusinessDay)

    public static DateTime GetNextBusinessDay(DateTime date)
    {
        DateTime current = date;

        while (true)
        {
            current = current.AddDays(1);

            if (IsBusinessDay(current))
            {
                return current;
            }
        }
    }
}
C#

使い方の例です。

DateTime d1 = new DateTime(2026, 2, 13); // 金
DateTime next1 = BusinessDayUtil.GetNextBusinessDay(d1);
// → 2026/02/16 (月)  土日を飛ばして月曜

DateTime d2 = new DateTime(2026, 2, 14); // 土
DateTime next2 = BusinessDayUtil.GetNextBusinessDay(d2);
// → 2026/02/16 (月)  土日を飛ばして月曜
C#

ここでの重要ポイントは、
「営業日判定を1箇所にまとめておいたおかげで、
“営業日を探すロジック”がとてもシンプルに書けている」ことです。


ステップ5:n営業日後を求める(締切計算など)

営業日ベースの加算ロジック

「3営業日以内に対応」「5営業日後が締切」のような要件では、
n営業日後を求める必要があります。

GetNextBusinessDay を応用して、
「n回分、営業日を進める」メソッドを作れます。

public static class BusinessDayUtil
{
    // 既存のメソッドは省略

    public static DateTime AddBusinessDays(DateTime start, int businessDays)
    {
        if (businessDays < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(businessDays), "負の値はこのメソッドでは扱いません。");
        }

        DateTime current = start;
        int remaining = businessDays;

        while (remaining > 0)
        {
            current = current.AddDays(1);

            if (IsBusinessDay(current))
            {
                remaining--;
            }
        }

        return current;
    }
}
C#

使い方の例です。

DateTime start = new DateTime(2026, 2, 13); // 金

DateTime after3 = BusinessDayUtil.AddBusinessDays(start, 3);
// 金の翌営業日は月 → 1
// 火 → 2
// 水 → 3
// → 2026/02/18 (水)

Console.WriteLine(after3);
C#

このように、
「営業日判定」と「営業日加算」はセットでユーティリティ化しておくと、
締切計算やリマインド日時のロジックがとても書きやすくなります。


実務での注意点:タイムゾーンと日付の扱い

営業日は「どの国・どのタイムゾーンのカレンダーか」を決めておく

営業日判定は、
基本的に「ある国・地域のカレンダー」に依存します。

日本の営業日なのか、
アメリカの営業日なのか、
グローバルに共通の営業日なのか。

ここを曖昧にしたまま DateTime を使うと、
UTCとローカルの変換で日付がズレて、
「サーバー上では前日扱いになっていた」
といった事故が起きます。

実務的には、

サーバー内部では UTC で日時を持つ
営業日判定をするときは、対象国のタイムゾーン(例: 日本なら “Tokyo Standard Time”)に変換してから日付部分を使う

という方針を決めておくと安全です。


まとめ 「営業日判定ユーティリティ」は“ビジネスルールをコードに閉じ込める器”

営業日判定は、
単に「土日かどうか」を見るだけでなく、
祝日・会社独自の休業日・国やタイムゾーンの違いなど、
ビジネスルールがぎゅっと詰まるポイントです。

押さえておきたいのは次のようなことです。

まずは DayOfWeek を使って「土日かどうか」を判定し、そのロジックを IsWeekend に閉じ込める。
「営業日=平日かつ祝日ではない」という定義を IsBusinessDay としてコードに表現し、祝日判定は IHolidayProvider のような差し替え可能な仕組みにする。
営業日判定をユーティリティ化しておくことで、「翌営業日」「n営業日後」といったロジックをシンプルに書けるようになる。
祝日データの持ち方(固定リスト、DB、外部APIなど)はユーティリティの外に追い出し、インターフェース越しに扱うと拡張しやすい。
どの国・どのタイムゾーンの営業日かを最初に決め、UTCとローカルの変換を意識して設計することで、日付のズレを防げる。

ここまで押さえておけば、
「なんとなく土日だけ見ている」状態から一歩進んで、
“ビジネスルールをきちんと反映した、実務で使える営業日判定ユーティリティ”を
自分のC#コードの中に自信を持って組み込めるようになります。

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