C#で休日判定


指定された日が休日かどうかを調べないといけなくなったので、C#でクラスを作った。
土日かどうかはDateTime型に.DayOfWeekをつけて判定でくるのだが、日本の祝日を調べる方法はどうもないらしい。
C#で出来ないなら、カレンダーの祝日情報を引っ張ってきて判定したらいいじゃない?と思って調べたらGoogleが提供しているけどAPI keyが…とか言ってるらしくめんどくさい。
個人が提供しているweb serviceもあるけど、いつ辞めるかわかないのでちょっと使いにくい。
日本政府が翌年までの祝日のCSVを提供しているので、それを定期的に取得して、それをもとに判定することにした。

使い方

Holiday hday = new Holiday();
string sDateTime = "2020-09-22";  //秋分の日
if (hday.isHoliday(DateTime.Parse(sDateTime)))
{
    Debug.WriteLine($"○ 日本の休日 {DateTime.Parse(sDateTime).ToString("yyyy-MM-dd (ddd)")}");
}
else
{
    Debug.WriteLine($"× 日本の休日 {DateTime.Parse(sDateTime).ToString("yyyy-MM-dd (ddd)")}");
}

Holidayクラス本体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.VisualBasic.FileIO;
using System.Net;
using System.Diagnostics;
using System.Collections.Specialized;
using Microsoft.VisualBasic.ApplicationServices;

namespace HolidayApp
{
    //休業日かどうかを調べるクラス
    // 日付を指定されたら、その日が休業日かどうか調べる
    class Holiday
    {
        private readonly string sSyukujitsuCSV = @"syukujitsu.csv";
        private readonly Dictionary<string, string> dicSyukujitsuCSV;
        private const string csDateFormat = "yyyy-MM-dd";

        public Holiday()  //コンストラクタ
        {
            Debug.WriteLine("Holiday(): START----------");

            if (!File.Exists(sSyukujitsuCSV)  //ファイル不存在
                || this.Days(File.GetCreationTime(sSyukujitsuCSV)) > 30)  //30日以上経過
            {
                if (this.DownloadHolidayList())
                {
                    Debug.WriteLine("Holiday(): Success to download Syukujitsu CSV file.");
                    File.SetCreationTime(sSyukujitsuCSV, DateTime.Now);  //上書きダウンロードになって作成日が更新されないので、強制する
                }
                else 
                {
                    Debug.WriteLine("Holiday(): Can not get Syukujitsu CSV file.");
                    throw new FileNotFoundException("can not get Syukujitsu CSV file.");
                }
            }

            //syukujitsu.csvを配列に取り込む
            dicSyukujitsuCSV = makeDicSyukujitsu();  //syukujitsu.csvを取り込む

            Debug.WriteLine("Holiday(): END----------");
        }

        public bool isHoliday(DateTime pDT)
        {
            //休業日 = 日本の祝日 + 土日 
            return isSyukujitsu(pDT) || isSatSun(pDT);
        }

        //DateTime を渡されたら、その日が休日かどうか判定する
        public bool isSyukujitsu(DateTime pDT)
        {
            Debug.WriteLine($"isSyukujitsu(): parameter=[{pDT}]");
            Debug.WriteLine($"isSyukujitsu(): key=[{pDT.ToString(csDateFormat)}]");
            return dicSyukujitsuCSV.ContainsKey(pDT.ToString(csDateFormat));
        }
        
        //今日が日本の祝日かどうか調べる。
        public bool isSyukujitsu()
        {
            return isSyukujitsu(DateTime.Now);
        }

        public bool isSatSun(DateTime pDT)
        {
            DayOfWeek dow = pDT.DayOfWeek;
            switch (dow)
            {
                case DayOfWeek.Saturday:  //土曜日
                    return true;
                case DayOfWeek.Sunday:    //日曜日
                    return true;
                default:
                    return false;
            }

#pragma warning disable CS0162
            return false;   //到達しないがお守りとしてout of order
#pragma warning restore CS0162
        }

        //syukujitsu.csvを読み込んで<日付, 祝日名>のDictionaryを作る
        //当日と同年以降のデータのみ収容する。
        //日付は yyyy-mm-dd 形式の文字列で格納する。
        private Dictionary<string, string> makeDicSyukujitsu()
        {
            Dictionary<string, string> CsvData = new Dictionary<string, string>();
            TextFieldParser tfparser = new TextFieldParser(sSyukujitsuCSV, System.Text.Encoding.GetEncoding("Shift_JIS"), true);  

            Debug.WriteLine("makeDicSyukujitsu(): START------------");

            using (tfparser)
            {
                tfparser.TextFieldType = FieldType.Delimited; //区切り形式
                tfparser.SetDelimiters(",");
                tfparser.HasFieldsEnclosedInQuotes = false;   //引用符なしとする
                tfparser.TrimWhiteSpace = true;               //空白文字を取り除く。(現状必要ないが念の為)

                //DateTime.Nowの年を取り出して、その年以降のものだけ格納しておきたい。

                DateTime dtDate;
                string sDate;
                while (!tfparser.EndOfData)
                {
                    string[] row = tfparser.ReadFields();
                    if (DateTime.TryParse(row[0], out dtDate))
                    {
                        if (dtDate.Year < DateTime.Now.Year)  // 今年より前のデータは無視。今年以降を格納する
                        {
                            continue;
                        }
                        sDate = dtDate.ToString(csDateFormat);
                    } else
                    {
                        continue;
                    }
                    // CsvData.Add(row[0], row[1]);  //コレクションに追加する
                    CsvData.Add(sDate, row[1]);  //コレクションに追加する
                }

                foreach (KeyValuePair<string, string> pair in CsvData)
                {
                    Debug.WriteLine($">> {pair.Key} : {pair.Value}"); 
                }
            }

            Debug.WriteLine("makeDicSyukujitsu(): START------------");
            return CsvData;
        }

        private int Days(DateTime pDateCreation)
        {
            TimeSpan ts = DateTime.Now - pDateCreation;
            Debug.WriteLine($"days(): Now - CreationDate (in days) = [{ts.Days}].");
            return ts.Days;
        }

        //日本政府が提供する休日リストを取得するメソッド
        public bool DownloadHolidayList()
        {
            string sURL = "https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv";
            var client = new WebClient();
            try
            {
                client.DownloadFile(sURL, sSyukujitsuCSV);
            }
            catch (WebException e)
            {
                Debug.WriteLine($"DownloadHolidayList(): Exception Message[{e.Message}]");
                return false;
            }
            return true;
        }
    }
}

シェアする

  • このエントリーをはてなブックマークに追加

フォローする