カテゴリ: C# 更新日: 2025/12/05

C#のif文の使い方を完全ガイド!初心者でもわかる乱数生成

C#で日本の祝日を判定する方法(カスタムロジック)
C#で日本の祝日を判定する方法(カスタムロジック)

先生と生徒の会話形式で理解しよう

生徒

「C#で日本の祝日を判定する方法を教えてください。どうやって今日が祝日かを知れるんですか?」

先生

「いい質問です。日本の祝日には、毎年同じ日付のものと、年によって変わるものがあります。例えば元日や建国記念の日は固定ですが、海の日や敬老の日のように何番目の月曜日かで決まるものもあります。C#で判定するにはこれらのルールを順番にチェックするカスタムロジックを書きます。」

生徒

「難しそうですが、具体的な例はありますか?」

先生

「はい。ここではわかりやすく、代表的な祝日ルールとC#のサンプルコードで説明します。」

1. 日本の祝日を判定する基本の考え方

1. 日本の祝日を判定する基本の考え方
1. 日本の祝日を判定する基本の考え方

日本の祝日判定はルールを整理することが重要です。主なルールは:

  • 固定祝日:毎年同じ月日(例:1月1日 = 元日、2月11日 = 建国記念の日)
  • ハッピーマンデー:何番目の月曜日かで決まる(例:第3月曜日など)
  • 春分・秋分:天文計算により年ごとに変わる(簡易式で近似可)
  • 振替休日:祝日にあたる日が日曜の場合、翌日が振替休日になるルール
  • 国民の休日:祝日に挟まれた平日は休日になる場合がある

これらを順にチェックすることで「今日は祝日か?」を判定できます。

2. 用語の説明(初心者向け)

2. 用語の説明(初心者向け)
2. 用語の説明(初心者向け)

固定祝日:毎年同じ日にやってくる祝日。日付をそのまま比較すれば判定できます。

ハッピーマンデー:祝日を月曜日に移動する制度。例えば「第3月曜日」は、その月の1日から数えて3つ目の月曜日を指します。

春分・秋分:本来は天体の位置で決まりますが、プログラムでは簡易的な計算式で近似します。年によって±1日の差が出ることがあります。

振替休日(ふりかえきゅうじつ):祝日が日曜日と重なると、翌平日が休みになる仕組みです。

3. C#での判定ステップ(全体像)

3. C#での判定ステップ(全体像)
3. C#での判定ステップ(全体像)
  1. 日付の年・月・日を取得する。
  2. 固定祝日リストと照合する。
  3. ハッピーマンデーの計算を行う(該当の月のN番目の月曜日を求める)。
  4. 春分・秋分を近似式で計算する。
  5. 祝日が見つかったら、振替休日ルールと国民の休日ルールを適用する。

これらを関数に分けて実装すると読みやすく、テストもしやすくなります。

4. 実際のC#サンプル(カスタムロジックの例)

4. 実際のC#サンプル(カスタムロジックの例)
4. 実際のC#サンプル(カスタムロジックの例)

下のコードは、基本的な固定祝日、ハッピーマンデー、春分日近似、振替休日を簡易に判定する例です。詳細な祝日法の改正や特殊ケースは反映していないので、運用時は最新版の祝日を確認してください。


using System;
using System.Collections.Generic;

public static class JapaneseHoliday
{
    private static readonly Dictionary<(int,int), string> FixedHolidays = new()
    {
        {(1,1), "元日"},
        {(2,11), "建国記念の日"},
        {(4,29), "昭和の日"},
        {(5,3), "憲法記念日"},
        {(5,4), "みどりの日"},
        {(5,5), "こどもの日"},
        {(11,3), "文化の日"},
        {(11,23), "勤労感謝の日"},
        {(2,23), "天皇誕生日"} // 例:現在の天皇の誕生日(変更の可能性あり)
    };

    public static bool IsHoliday(DateTime date)
    {
        if (IsFixedHoliday(date)) return true;
        if (IsHappyMonday(date)) return true;
        if (IsVernalEquinox(date) || IsAutumnalEquinox(date)) return true;
        // 振替休日と国民の休日の判定を行う(簡易版)
        if (IsSubstituteHoliday(date)) return true;
        if (IsCitizenHoliday(date)) return true;
        return false;
    }

    private static bool IsFixedHoliday(DateTime d)
    {
        return FixedHolidays.ContainsKey((d.Month, d.Day));
    }

    private static bool IsHappyMonday(DateTime d)
    {
        // 例: 海の日(第3月曜日)や敬老の日(第3月曜日)など
        // ここでは第3月曜日の例として実装
        if (d.DayOfWeek != DayOfWeek.Monday) return false;
        var first = new DateTime(d.Year, d.Month, 1);
        int mondayCount = 0;
        for (int i = 0; i < DateTime.DaysInMonth(d.Year, d.Month); i++)
        {
            var day = first.AddDays(i);
            if (day.DayOfWeek == DayOfWeek.Monday)
            {
                mondayCount++;
                if (day.Day == d.Day && mondayCount == 3) return true;
            }
        }
        return false;
    }

    private static bool IsVernalEquinox(DateTime d)
    {
        // 春分日の簡易計算(近似式)
        int y = d.Year;
        int day = (int)(20.69115 + 0.2421904 * (y - 2000) - (y - 2000) / 4);
        return d.Month == 3 && d.Day == day;
    }

    private static bool IsAutumnalEquinox(DateTime d)
    {
        int y = d.Year;
        int day = (int)(23.09 + 0.2421904 * (y - 2000) - (y - 2000) / 4);
        return d.Month == 9 && d.Day == day;
    }

    private static bool IsSubstituteHoliday(DateTime d)
    {
        // 簡易実装:前日が祝日で、前日が日曜なら振替と見なす
        var prev = d.AddDays(-1);
        if (prev.DayOfWeek == DayOfWeek.Sunday && (IsFixedHoliday(prev) || IsHappyMonday(prev) || IsVernalEquinox(prev) || IsAutumnalEquinox(prev)))
            return true;
        return false;
    }

    private static bool IsCitizenHoliday(DateTime d)
    {
        // 簡易:前日と翌日が祝日なら国民の休日
        var prev = d.AddDays(-1);
        var next = d.AddDays(1);
        if ((IsFixedHoliday(prev) || IsHappyMonday(prev) || IsVernalEquinox(prev) || IsAutumnalEquinox(prev))
            && (IsFixedHoliday(next) || IsHappyMonday(next) || IsVernalEquinox(next) || IsAutumnalEquinox(next)))
            return true;
        return false;
    }
}

使い方の一例:


var today = DateTime.Today;
Console.WriteLine($"{today:yyyy-MM-dd} は祝日ですか? {JapaneseHoliday.IsHoliday(today)}");

2025-01-01 は祝日ですか? True

5. 実運用で注意するポイント

5. 実運用で注意するポイント
5. 実運用で注意するポイント
  • 祝日法の改正で日付やルールが変わる可能性があるため、最新版の情報を確認してください。
  • 春分・秋分は簡易式だと年によって誤差が出るため、正確性が必要な場合は天文データや公式カレンダーを使いましょう。
  • 天皇誕生日などは即位により日付が変わることがあるので、固定値に頼りすぎない設計を推奨します。
  • タイムゾーンやローカルのカレンダー処理に注意。DateTimeKindやUTC変換の扱いにも気を配りましょう。

6. テストと確認のしかた(初心者向け)

6. テストと確認のしかた(初心者向け)
6. テストと確認のしかた(初心者向け)

いくつかの日付を用意して、期待する結果と照らし合わせる単純なテストを書きましょう。例えば元日、海の日(第3月曜日)、春分の日の近似日、日曜日に重なる祝日の振替などをチェックします。

手作業でも良いですが、単体テストフレームワーク(例:NUnit、xUnit)を使うと自動化できて便利です。

7. まとめ代わりの補足(ここでは要点のみ)

7. まとめ代わりの補足(ここでは要点のみ)
7. まとめ代わりの補足(ここでは要点のみ)

・ルールを整理して順に判定すること。固定祝日、ハッピーマンデー、春分秋分、振替、国民の休日の順でチェックすると実装が分かりやすいです。

・簡易実装は学習用としては十分ですが、本番運用では公式データの取り込みを検討してください。

8. ハッピーマンデーの考え方をやさしく説明

8. ハッピーマンデーの考え方をやさしく説明
8. ハッピーマンデーの考え方をやさしく説明

「ハッピーマンデー」は、祝日を月曜日に集めることで連休を作りやすくする制度です。たとえば「第3月曜日」は、その月の最初の月曜日を1回目として数え、3回目に当たる日を指します。イメージとしてはカレンダーの月曜日に印をつけていって、3つ目の印の日が祝日だと覚えるとわかりやすいです。

プログラムでは、ある月の1日から順に調べて「月曜日が何回目か」を数え、対象の日と一致するかを判定します。先ほどのサンプル関数 IsHappyMonday は、その考え方をそのままコードにしたものです。

9. 春分・秋分の近似式について(もう少し丁寧に)

9. 春分・秋分の近似式について(もう少し丁寧に)
9. 春分・秋分の近似式について(もう少し丁寧に)

春分日と秋分日は天体の運行によって決まりますが、簡易式を使えばほとんどの年で正しい日を計算できます。式の中で使われている数値は統計的に求められた近似値です。プログラムで使う場合は下記の点に注意してください:

  • 簡易式は数年単位で正しいが、うるう年の影響や微調整でズレが生じることがある。
  • 高い正確性が必要なら、国立天文台などの公式データをAPIやCSVで取得して使う。

10. 初心者向けのやさしいたとえ

10. 初心者向けのやさしいたとえ
10. 初心者向けのやさしいたとえ

祝日判定のプログラムは、台所で料理を作る手順に似ています。材料(ルール)を用意し、手順(判定の順序)に沿って一つずつ確認します。材料が揃っていれば料理(判定結果)は期待通りになります。材料が古かったり間違っていれば味(判定)が変わってしまうので、最新版の材料を使うことが大切です。

11. よくある質問(FAQ)

11. よくある質問(FAQ)
11. よくある質問(FAQ)

Q. 祝日がいつ変更されたか分かる方法は?
A. 日本の祝日は法律で定められているため、内閣府や官報、または公式サイトで変更履歴を確認できます。開発では公式データを取得する仕組みを作ると安心です。

Q. すべての祝日を自分で実装する必要がありますか?
A. 学習目的なら自前実装で仕組みを学ぶのは良いですが、実運用では公式カレンダーやライブラリ(外部パッケージ)を使う方が安全で手間が省けます。

12. 振替休日と国民の休日の細かいルール(実務で重要)

12. 振替休日と国民の休日の細かいルール(実務で重要)
12. 振替休日と国民の休日の細かいルール(実務で重要)

振替休日は、祝日が日曜日に当たると翌平日が休みになるルールです。ただし、複数の祝日が連続する場合や法改正のタイミングで挙動が変わることがあります。国民の休日は、祝日に挟まれた日が平日であればその日も休日になるルールですが、祝日と祝日の間に元々祝日がある場合は適用されないなどの例外も存在します。

こうした例外処理を見落とすと判定が誤るため、実際に運用する際は公式の判定ルールを参照して、コードに反映してください。

13. 実装を良くするためのヒント

13. 実装を良くするためのヒント
13. 実装を良くするためのヒント
  • 祝日のデータを外部ファイル(JSONやCSV)にしておき、法改正があったらファイルだけ差し替えられる設計にすると便利です。
  • キャッシュを使って同じ年の祝日一覧を一度だけ計算するようにすると高速になります。
  • テストケースを豊富に用意して、過去数年分と将来数年分で期待する振る舞いを確認しましょう。
  • DateTimeの扱いではDateTimeKindに注意し、タイムゾーンが絡む処理はUTCへ変換してから判定するなどの工夫をしましょう。

14. 具体的な判定の流れ(例で見る)

14. 具体的な判定の流れ(例で見る)
14. 具体的な判定の流れ(例で見る)

例:2025年7月の第3月曜日を調べる場合、まずその月の1日から順に月曜日を数えます。3つ目の月曜日に該当する日付が見つかれば、それは祝日(海の日など)です。同様に、3月の春分日が近似式で20日と算出されれば、3月20日を祝日として扱います。

最後に、いくつかの異なる日付でプログラムを動かして結果を目で確認すると安心です。

15. ライブラリや公式データの活用

15. ライブラリや公式データの活用
15. ライブラリや公式データの活用

自前実装の代わりに、祝日判定ライブラリや政府の公開カレンダーを利用する方法もあります。公式データを使うと法改正への対応が容易になり、実務での信頼性が高まります。

16. 最後に(初心者への一言)

16. 最後に(初心者への一言)
16. 最後に(初心者への一言)

最初は難しく見えますが、ルールを分解して一つずつ実装すれば必ず理解できます。まずは今回のサンプルを動かしてみて、少しずつ改良していきましょう。

カテゴリの一覧へ
新着記事
New1
C#
C#のメモリ管理とガーベジコレクションの基礎を理解しよう
New2
C#
C#の参照型と値型の違いを初心者向けにやさしく解説!
New3
C#
C#のクエリ式とメソッド式の書き換え方を完全ガイド!LINQの2つの書き方をマスター
New4
C#
C#の戻り値にタプルを使う方法!複数の値を返すテクニック
人気記事
No.1
Java&Spring記事人気No1
C#
C#で文字列が数値か判定する方法を解説!char.IsDigitやTryParseの基本
No.2
Java&Spring記事人気No2
C#
C#のLINQでOrderByを使った並び替えを完全ガイド!初心者でもわかるソート方法
No.3
Java&Spring記事人気No3
C#
C#のpartialクラスとは?初心者でも理解できるクラス分割の基本
No.4
Java&Spring記事人気No4
C#
C#のrefとoutキーワードとは?引数の参照渡しを理解しよう
No.5
Java&Spring記事人気No5
COBOL
COBOLの数値データ型「PIC 9」の使い方と注意点をやさしく解説!
No.6
Java&Spring記事人気No6
C#
C#の引数と戻り値の基本!値を受け渡し・返す仕組みを理解しよう
No.7
Java&Spring記事人気No7
C#
C#のラムダ式の書き方と構文を初心者向けに完全解説
No.8
Java&Spring記事人気No8
C#
C#で型を調べる方法!GetType()・typeof演算子の違いと使い方