はじめに 「営業日加算」は“ビジネスの締切をコードに落とす技”
「3営業日以内に対応」「5営業日後が締切」「翌営業日に処理」――
こういう要件を“ちゃんと”満たすには、
単純な「日数加算」ではなく「営業日加算」が必要になります。
DateTime.AddDays(3) は「3日後」ですが、
土日や祝日を飛ばしてくれたりはしません。
そこで登場するのが「営業日加算ユーティリティ」です。
ここでは、
土日だけを飛ばすシンプル版から始めて、
祝日対応・設計のポイントまで、
初心者向けにかみ砕いて説明していきます。
基本の考え方:1日ずつ進めて「営業日だけカウントする」
まずは「営業日とは何か」を決める
営業日加算の前に、
「営業日とは何か」をコードで定義しておく必要があります。
一番シンプルな定義はこうです。
- 土日以外の日 → 営業日
この定義をそのままメソッドにすると、こうなります。
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 IsBusinessDay(DateTime date)
{
return !IsWeekend(date);
}
}
C#この「営業日判定」を土台にして、
「営業日加算」を組み立てていきます。
営業日を n 日進める基本ロジック
考え方はシンプルで、
- 日付を1日ずつ進める
- 進めた日が営業日ならカウンタを1減らす
- カウンタが0になったところが「n営業日後」
という流れです。
public static class BusinessDayUtil
{
public static bool IsWeekend(DateTime date)
{
DayOfWeek w = date.DayOfWeek;
return w == DayOfWeek.Saturday || w == DayOfWeek.Sunday;
}
public static bool IsBusinessDay(DateTime date)
{
return !IsWeekend(date);
}
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#ここでのポイントは、
- 「営業日かどうか」の判定を
IsBusinessDayに閉じ込めていること - 加算ロジックは「1日ずつ進める」だけにして、シンプルさを保っていること
です。
具体例でイメージを固める
金曜日から3営業日後を求める
例えば、2026/2/13(金)から3営業日後を求めてみます。
DateTime start = new DateTime(2026, 2, 13); // 金
DateTime after3 = BusinessDayUtil.AddBusinessDays(start, 3);
Console.WriteLine(after3); // 2026/02/18 (水)
C#頭の中で追ってみると、こうなります。
- 2/14(土) → 営業日ではない → カウントしない
- 2/15(日) → 営業日ではない → カウントしない
- 2/16(月) → 営業日 → 1日目
- 2/17(火) → 営業日 → 2日目
- 2/18(水) → 営業日 → 3日目 → ここで終了
このように、
土日を自動で飛ばしてくれるので、
「3営業日後」のような要件をそのままコードにできます。
すでに土日の場合はどうなるか
例えば、開始日が土曜日だった場合。
DateTime start = new DateTime(2026, 2, 14); // 土
DateTime after1 = BusinessDayUtil.AddBusinessDays(start, 1);
Console.WriteLine(after1); // 2026/02/16 (月)
C#- 2/15(日) → 営業日ではない
- 2/16(月) → 営業日 → 1日目 → 終了
「開始日が営業日かどうか」はカウントに含めず、
「翌日以降の営業日を数える」仕様になっていることに注意してください。
「開始日が営業日なら、それも1日目に含めたい」
という要件なら、ロジックを少し変える必要があります。
仕様の違い:「開始日を含めるかどうか」をはっきり決める
2つのよくあるパターン
営業日加算には、よくある2つの解釈があります。
- 「開始日の翌日から数えて n 営業日後」
- 「開始日を1日目として数えて n 営業日目」
今の実装は 1 のパターンです。
もし 2 のパターンにしたいなら、
「開始日が営業日なら、最初から1日消費しておく」
という形に変えられます。
public static DateTime AddBusinessDaysInclusive(DateTime start, int businessDays)
{
if (businessDays <= 0)
{
throw new ArgumentOutOfRangeException(nameof(businessDays), "1以上を指定してください。");
}
DateTime current = start;
int remaining = businessDays;
if (IsBusinessDay(current))
{
remaining--;
}
while (remaining > 0)
{
current = current.AddDays(1);
if (IsBusinessDay(current))
{
remaining--;
}
}
return current;
}
C#この仕様の違いは、
締切や SLA(サービスレベル)の解釈に直結します。
実務では、
- どちらの解釈にするかを要件として明文化する
- メソッド名やコメントで「開始日を含む/含まない」をはっきり書く
ことがとても重要です。
祝日を含めた「実務的な営業日加算」にする
営業日=平日かつ祝日ではない
多くの日本の業務システムでは、
- 土日
- 祝日
を休業日とみなします。
その場合、営業日の定義はこうなります。
- 営業日=土日ではない かつ 祝日ではない
この定義をコードに落とし込むと、こうです。
public interface IHolidayProvider
{
bool IsHoliday(DateTime date);
}
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);
}
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#祝日の中身(どの日が祝日か)は、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 の実装を差し替えるだけで済みます。
タイムゾーンと「どの国の営業日か」を意識する
営業日は“カレンダーの国とタイムゾーン”に依存する
営業日加算は、
「どの国のカレンダーか」「どのタイムゾーンか」に強く依存します。
日本の営業日なのか、
アメリカの営業日なのか、
グローバル共通の営業日なのか。
ここを曖昧にしたまま DateTime を扱うと、
UTCとローカルの変換で日付がズレて、
「サーバーでは前日扱いになっていた」
といった事故が起きます。
実務的には、
- サーバー内部では UTC で日時を持つ
- 営業日判定・営業日加算をするときは、対象国のタイムゾーン(例: 日本なら “Tokyo Standard Time”)に変換してから日付部分を使う
という方針を決めておくと安全です。
まとめ 「営業日加算ユーティリティ」は“ビジネスの約束を守るための道具”
営業日加算は、
単なる日付計算ではなく、
「いつまでに対応するか」「いつが締切か」という
ビジネス上の約束をコードに落とし込むための重要な仕組みです。
押さえておきたいポイントは次の通りです。
- 営業日加算の土台は「営業日判定」であり、
IsBusinessDayにロジックを集約しておくと、加算処理がシンプルになる。 - 基本ロジックは「1日ずつ進めて、営業日だけカウントする」形で書くと、初心者でも理解しやすく、バグも少ない。
- 「開始日を含めるかどうか」は仕様として必ず決め、メソッド名やコメントで明示する。
- 祝日を含めた実務的な営業日加算にするには、祝日判定を
IHolidayProviderのような差し替え可能な仕組みに切り出す。 - どの国・どのタイムゾーンの営業日かを最初に決め、UTCとローカルの変換を意識して設計することで、日付のズレを防げる。
ここまで押さえておけば、
「なんとなく日数を足している」状態から一歩進んで、
“ビジネスの締切と約束をきちんと守れる、実務で使える営業日加算ユーティリティ”を
自分のC#コードの中に自信を持って組み込めるようになります。
