カテゴリ: C# 更新日: 2026/03/06

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. 最後に(初心者への一言)

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

まとめ

まとめ
まとめ

ここまでC#を用いた日本の祝日判定ロジックについて詳しく解説してきました。プログラミングにおいて、一見複雑に見える「カレンダーのルール」をコードに落とし込む作業は、論理的思考を鍛える絶好の題材です。日本の祝日には、固定の日付だけでなく、ハッピーマンデー制度や天文学的な計算が必要な春分・秋分の日、さらには振替休日や国民の休日といった連動するルールが組み合わさっています。これらを一つひとつ整理し、if文や関数を組み合わせて実装していくプロセスは、C#の基礎から応用までを学ぶ上で非常に有意義です。

C#で祝日判定を実装する際の重要ポイント

本記事で学んだ内容を振り返り、実務や個人開発で役立つポイントを再確認しましょう。

  • 判定の優先順位を意識する: まずは固定祝日をチェックし、次に移動祝日(ハッピーマンデー)、そして計算が必要な祝日、最後に振替休日や国民の休日という順番でロジックを組むと、コードがスッキリと整理されます。
  • DateTime構造体の活用: DayOfWeekプロパティを使えば、その日が何曜日であるかを簡単に取得できます。これはハッピーマンデーや振替休日の判定に欠かせない機能です。
  • メンテナンス性の確保: 祝日法は改正されることがあります。コードの中に日付を直接書き込む(ハードコーディングする)のではなく、設定ファイルやデータベース、あるいは外部のAPIを活用することで、変更に強いプログラムになります。

さらに一歩進んだサンプルコード:祝日名まで取得する

これまでの学習を踏まえ、単に「祝日かどうか」を判定するだけでなく、「何の祝日か」という名称まで返却する、より実用的なメソッドの構成例を見てみましょう。


using System;
using System.Collections.Generic;

public class HolidayChecker
{
    // 祝日名を管理する辞書
    private static readonly Dictionary<(int, int), string> FixedHolidays = new Dictionary<(int, int), string>
    {
        { (1, 1), "元日" },
        { (2, 11), "建国記念の日" },
        { (2, 23), "天皇誕生日" },
        { (4, 29), "昭和の日" },
        { (5, 3), "憲法記念日" },
        { (5, 4), "みどりの日" },
        { (5, 5), "こどもの日" },
        { (11, 3), "文化の日" },
        { (11, 23), "勤労感謝の日" }
    };

    public static string GetHolidayName(DateTime targetDate)
    {
        int year = targetDate.Year;
        int month = targetDate.Month;
        int day = targetDate.Day;

        // 1. 固定祝日のチェック
        if (FixedHolidays.TryGetValue((month, day), out string name))
        {
            return name;
        }

        // 2. ハッピーマンデーのチェック(例:成人の日、海の日、敬老の日、スポーツの日)
        if (IsHappyMonday(targetDate, 1, 2, DayOfWeek.Monday)) return "成人の日";
        if (IsHappyMonday(targetDate, 7, 3, DayOfWeek.Monday)) return "海の日";
        if (IsHappyMonday(targetDate, 9, 3, DayOfWeek.Monday)) return "敬老の日";
        if (IsHappyMonday(targetDate, 10, 2, DayOfWeek.Monday)) return "スポーツの日";

        // 3. 春分・秋分の日のチェック
        if (month == 3 && day == CalculateVernalEquinox(year)) return "春分の日";
        if (month == 9 && day == CalculateAutumnalEquinox(year)) return "秋分の日";

        // 4. 振替休日のチェック
        if (CheckSubstituteHoliday(targetDate)) return "振替休日";

        return null; // 祝日でない場合はnullを返す
    }

    private static bool IsHappyMonday(DateTime d, int targetMonth, int weekIndex, DayOfWeek targetDayOfWeek)
    {
        if (d.Month != targetMonth || d.DayOfWeek != targetDayOfWeek) return false;
        int nth = (d.Day - 1) / 7 + 1;
        return nth == weekIndex;
    }

    private static int CalculateVernalEquinox(int year)
    {
        return (int)(20.8431 + 0.242194 * (year - 1980) - (year - 1980) / 4);
    }

    private static int CalculateAutumnalEquinox(int year)
    {
        return (int)(23.2488 + 0.242194 * (year - 1980) - (year - 1980) / 4);
    }

    private static bool CheckSubstituteHoliday(DateTime d)
    {
        if (d.DayOfWeek == DayOfWeek.Monday)
        {
            // 前日が祝日なら振替休日(簡易的な判定)
            return GetHolidayName(d.AddDays(-1)) != null;
        }
        return false;
    }
}

このコードを実行して、特定の日付が何の祝日であるかを出力してみましょう。


DateTime testDate = new DateTime(2025, 5, 5);
string holidayName = HolidayChecker.GetHolidayName(testDate);
Console.WriteLine($"{testDate:yyyy/MM/dd} は {holidayName} です。");

// 出力結果:
2025/05/05 は こどもの日 です。

COBOLでの実装イメージ(参考)

歴史的なシステムや金融機関などで今も現役のCOBOLでは、日付処理をどのように記述するのでしょうか。C#とは書き味が大きく異なりますが、ロジックの根底は同じです。


IDENTIFICATION DIVISION.
PROGRAM-ID. HOLIDAY-CHECK.
DATA DIVISION.
WORKING-STORAGE SECTION.
01  W-DATE.
    05  W-YEAR  PIC 9(04).
    05  W-MONTH PIC 9(02).
    05  W-DAY   PIC 9(02).
01  W-IS-HOLIDAY PIC X(01) VALUE 'N'.

PROCEDURE DIVISION.
    MOVE 2025 TO W-YEAR.
    MOVE 01   TO W-MONTH.
    MOVE 01   TO W-DAY.

    IF W-MONTH = 01 AND W-DAY = 01
        DISPLAY "GANJITSU - HAPPY NEW YEAR"
        MOVE 'Y' TO W-IS-HOLIDAY
    END-IF.
    
    STOP RUN.

これからの学習に向けて

今回はC#を中心に祝日判定のロジックを学びましたが、これを応用して「営業日カレンダー」や「予約システム」など、実際のアプリケーション開発に挑戦してみてください。日付の操作に慣れることは、エンジニアとしてのスキルを大きく飛躍させる一歩となります。 また、より高度な開発を目指すなら、内閣府が公開している「国民の祝日」のCSVデータをプログラムで読み込んで動的に判定する仕組みを作ってみるのも面白いでしょう。

先生と生徒の振り返り会話

生徒

「先生、ありがとうございました!一見複雑な祝日のルールも、一つずつ分解してif文で書いていくと、意外と自分でも実装できそうな気がしてきました。」

先生

「その意気です!プログラミングは複雑な問題を小さな要素に分ける作業そのものですからね。特に日本の祝日は、法律に基づいた明確なアルゴリズムがあるので、練習には最適なんですよ。」

生徒

「ハッピーマンデーの判定で、『(d.Day - 1) / 7 + 1』という計算を使って何週目かを出しているのが面白いですね。これならカレンダーを1日から全部ループさせなくても判定できます。」

先生

「よく気づきましたね。効率的な計算式を考えるのもプログラミングの醍醐味です。ただ、春分の日や秋分の日のように、計算式だけでは将来的にズレる可能性があるものは注意が必要ですよ。」

生徒

「なるほど。だから実務では公式データやライブラリを使うのが推奨されるんですね。まずはこの基本コードを自分で改造して、振替休日の完璧な判定に挑戦してみます!」

先生

「素晴らしい!もし2026年やそれ以降の祝日を判定したい場合は、ぜひ自分でテストケースを書いて、正しく動くか試してみてください。応援していますよ。」

カテゴリの一覧へ
新着記事
New1
COBOL
COBOLのインデントと可読性の高いコードの書き方を徹底解説!初心者でも読みやすいプログラムの基本
New2
C#
C#のLINQでWhere・Select・OrderByを使う方法を完全解説!初心者でもわかる基本操作
New3
C#
C#のxUnitテスト入門!初心者でもわかるデバッグと自動テストの基本
New4
Azure
Azure SQL Databaseのリードスケールアウトとは?参照負荷分散でパフォーマンスを高速化する方法
人気記事
No.1
Java&Spring記事人気No1
C#
C#の文字列を数値に変換する方法(int.Parse・TryParse)をわかりやすく解説!
No.2
Java&Spring記事人気No2
C#
C#のメソッドとは?基本の定義と呼び出し方を初心者向けに解説
No.3
Java&Spring記事人気No3
C#
C#で文字列が数値か判定する方法を解説!char.IsDigitやTryParseの基本
No.4
Java&Spring記事人気No4
C#
C#でswitch式を使う方法!C# 8.0以降の新機能を解説
No.5
Java&Spring記事人気No5
Azure
Azure Bastionの使い方を徹底解説!踏み台サーバー不要で安全にRDP/SSH接続
No.6
Java&Spring記事人気No6
C#
C#のプロパティとは?get/setアクセサの書き方と使い分け
No.7
Java&Spring記事人気No7
C#
C#の日付型(DateTime)と基本的な使い方を解説|初心者向け入門ガイド
No.8
Java&Spring記事人気No8
C#
C#の引数と戻り値の基本!値を受け渡し・返す仕組みを理解しよう