祝日判定は「営業日・締め日・勤怠を正しく扱うための“前提条件”になるユーティリティです」
業務システムでは、次のような場面で「その日が祝日かどうか」を判定したくなります。
- 締め日や支払期日を「営業日ベース」で計算したい
- 勤怠で「祝日は出勤扱いにしない」ルールを入れたい
- 予約システムで「祝日は受付停止」にしたい
- バッチ処理を「平日だけ動かす」ようにしたい
ここで祝日判定を間違えると、 支払期日がずれたり、勤怠が誤集計されたり、予約が取れてはいけない日に取れてしまったりと、 業務的なインパクトが非常に大きくなります。 だからこそ、祝日判定ユーティリティは日付・時間処理の中でも重要度が高い機能になります。
祝日判定の基本は「祝日データをどこからどう持つか」を決めることです
固定祝日と“動く祝日”の両方を扱う必要があります
日本の祝日は、大きく次の2種類に分かれます。
- 固定祝日:元日(1/1)、建国記念の日(2/11)、憲法記念日(5/3)など、毎年同じ日付
- 動く祝日:成人の日(1月第2月曜)、海の日(7月第3月曜)など、“ハッピーマンデー”で動く祝日
さらに、「振替休日」「国民の休日」「天皇即位関連」など、 年によって変わるものもあります。
このため、祝日判定を自前で完全に実装するのはかなり大変で、 「祝日データをどう管理するか」が設計の肝になります。
シンプルな方法:自前で「祝日一覧」を持って判定するユーティリティです
小規模・限定的なシステムなら「テーブル+検索」で十分なこともあります
まずは、考え方が分かりやすい「自前テーブル方式」を見てみます。 「このシステムでは、この期間だけ祝日を扱えればよい」という前提なら、 固定の一覧を持っておくだけでも実務的に使えます。
using System;
using System.Collections.Generic;
using System.Linq;
public static class SimpleHolidayUtility
{
// 例: 2024年だけを対象にした簡易版
private static readonly HashSet<DateTime> Holidays2024 = new HashSet<DateTime>
{
new DateTime(2024, 1, 1), // 元日
new DateTime(2024, 1, 8), // 成人の日
new DateTime(2024, 2, 11), // 建国記念の日
new DateTime(2024, 2, 12), // 振替休日
// …必要な分だけ追加…
};
public static bool IsHoliday(DateTime date)
{
if (date.Year != 2024) return false; // 対象外はとりあえず平日扱い
return Holidays2024.Contains(date.Date);
}
}
C#使い方は次の通りです。
Console.WriteLine(SimpleHolidayUtility.IsHoliday(new DateTime(2024, 1, 1))); // true
Console.WriteLine(SimpleHolidayUtility.IsHoliday(new DateTime(2024, 1, 2))); // false
C#この方法のメリット・デメリットは次の通りです。
- メリット:実装が簡単で、初心者にも分かりやすい
- デメリット:年ごとにデータを更新する必要があり、長期運用には向かない
ここでの重要ポイントは、 「祝日判定は“どこまでの期間・精度が必要か”によって実装方針が変わる」 ということです。
実務的な方法:公式祝日データを扱うライブラリを利用する設計です
日本の祝日を扱うライブラリを使うと、精度と保守性が一気に上がります
日本の祝日を扱う .NET ライブラリとして、 内閣府が公開している「国民の祝日」CSVを扱う JpPublicHolidays があります。
このライブラリは、NuGet からインストールして次のように使えます。
using JpPublicHolidays;
// 祝日一覧を取得(非同期)
var holidays = await PublicHolidays.Get();
// 特定の日付が祝日かどうか
bool isHoliday = holidays.Any(h => h.Date.Date == new DateTime(2025, 1, 1).Date);
C#さらに、同ライブラリにはインメモリデータベース機能があり、 db.IsHoliday(date) のように高速に判定できます。
using JpPublicHolidays;
// APIから祝日データベースを作成
var db = await HolidayDatabase.CreateFromApiAsync();
// 祝日判定
bool isHolidayJan1 = db.IsHoliday(new DateTime(2025, 1, 1)); // true
bool isHolidayJan2 = db.IsHoliday(new DateTime(2025, 1, 2)); // false
C#ここでの重要ポイントは、 「祝日ルールは毎年変わることがあるため、公式データを扱うライブラリを使う方が保守性が高い」 ということです。
業務で使いやすい「祝日判定ユーティリティ」のテンプレートです
ライブラリをラップして「業務コードからはシンプルに呼べる形」にします
外部ライブラリをそのまま業務コードに散らすのではなく、 自前のユーティリティでラップしておくと、後から差し替えやすくなります。
using System;
using System.Threading.Tasks;
using JpPublicHolidays;
public static class JapanHolidayUtility
{
private static HolidayDatabase? _db;
public static async Task InitializeAsync()
{
// 一度だけロードしてキャッシュ
_db ??= await HolidayDatabase.CreateFromApiAsync();
}
public static bool IsHoliday(DateTime date)
{
if (_db == null)
{
throw new InvalidOperationException("JapanHolidayUtility is not initialized.");
}
return _db.IsHoliday(date.Date);
}
public static bool IsBusinessDay(DateTime date)
{
if (_db == null)
{
throw new InvalidOperationException("JapanHolidayUtility is not initialized.");
}
// 土日 or 祝日は営業日ではない
if (date.DayOfWeek == DayOfWeek.Saturday ||
date.DayOfWeek == DayOfWeek.Sunday)
{
return false;
}
return !_db.IsHoliday(date.Date);
}
}
C#使い方は次の通りです。
await JapanHolidayUtility.InitializeAsync();
DateTime d1 = new DateTime(2025, 1, 1);
DateTime d2 = new DateTime(2025, 1, 2);
Console.WriteLine(JapanHolidayUtility.IsHoliday(d1)); // true
Console.WriteLine(JapanHolidayUtility.IsBusinessDay(d1)); // false
Console.WriteLine(JapanHolidayUtility.IsBusinessDay(d2)); // true
C#ここでの重要ポイントは、
- 初期化処理を一箇所にまとめていること
- 祝日判定と営業日判定を分けていること
です。 これにより、業務コード側では「営業日かどうか」をシンプルに呼び出せます。
祝日判定を「締め日・期日計算」と組み合わせます
「期日が祝日なら翌営業日にずらす」といった業務ルールを自然に書けます
例えば、支払期日を「月末の翌営業日」にしたい場合、 次のようなユーティリティが書けます。
public static DateTime GetNextBusinessDay(DateTime date)
{
DateTime current = date;
while (!JapanHolidayUtility.IsBusinessDay(current))
{
current = current.AddDays(1);
}
return current;
}
public static DateTime GetPaymentDueDate(int year, int month)
{
// 月末を求める
int days = DateTime.DaysInMonth(year, month);
DateTime endOfMonth = new DateTime(year, month, days);
// 月末の翌営業日
DateTime nextDay = endOfMonth.AddDays(1);
return GetNextBusinessDay(nextDay);
}
C#使い方は次の通りです。
await JapanHolidayUtility.InitializeAsync();
Console.WriteLine(GetPaymentDueDate(2025, 1)); // 2025年1月の支払期日(祝日・土日を避けた日)
C#ここでの重要ポイントは、 祝日判定ユーティリティがあることで、「営業日ベースの期日計算」を業務コードに自然な形で落とし込める ということです。
祝日判定を「勤怠・予約・バッチ」のルールと組み合わせます
「祝日は出勤不可」「祝日は予約不可」「祝日はバッチ停止」などを一箇所で表現できます
例えば、勤怠入力で「祝日は原則出勤不可」としたい場合、 次のようなチェックができます。
public static bool CanWorkOn(DateTime date)
{
// 祝日・土日は原則不可
return JapanHolidayUtility.IsBusinessDay(date);
}
C#予約システムで「祝日は予約不可」にしたい場合はこうです。
public static bool CanReserve(DateTime date)
{
// 営業日のみ予約可能
return JapanHolidayUtility.IsBusinessDay(date);
}
C#バッチ処理で「祝日は動かさない」場合は、 スケジューラ側で次のような条件を入れます。
if (!JapanHolidayUtility.IsBusinessDay(DateTime.Today))
{
// 今日は祝日 or 土日なのでバッチをスキップ
return;
}
C#ここでの重要ポイントは、 祝日判定ユーティリティを“業務ルールの入り口”として使うことで、 勤怠・予約・バッチなど複数の機能を一貫したカレンダールールで動かせる ということです。
まとめ:祝日判定は「日本のカレンダーを業務ロジックに正しく埋め込むためのユーティリティ」です
祝日判定の本質は、
- 祝日データを正しく管理し
- その日が祝日かどうかを安全に判定し
- 営業日・期日・勤怠・予約・バッチなどの業務ルールに一貫して反映すること
にあります。
押さえておきたいポイントは、
- 祝日は固定日だけでなく“動く祝日”や振替休日があるため、自前実装は慎重にすべきこと
- 小規模なら自前テーブル方式でもよいが、長期運用なら公式データを扱うライブラリ利用が現実的であること
- ユーティリティ化しておくことで、祝日判定と営業日判定を業務コードからシンプルに呼べること
- 期日計算・勤怠・予約・バッチなど、複数機能を同じカレンダールールで動かせること
多くの購読者のみなさんが日本向けの業務コードを書くとき、 この「祝日判定ユーティリティ」を導入しておくだけで、 カレンダーまわりのロジックが安定し、 支払期日・勤怠・予約・バッチ処理のトラブルを大幅に減らすことができます。
