祝日を返すマクロ [Excel VBA]
2024/03/26 05:56
使うためには、fnWeekday 関数(Public 関数)を Excel のセルに記述して利用してください。
少なくとも、2023年~2025年は問題なさそうです。
(2023.6.25 2025年の「敬老の日」が祝日にならない問題を修正)
(2024.3.2 Date 関数の戻り値が日付型と判定できない問題を修正)
最終的に挙動を確認した Excel バージョンは、次の通りです。
Microsoft® Excel® for Microsoft 365 MSO (バージョン 2401 ビルド 16.0.17231.20236) 64 ビット
仕様
モジュール
モジュール内の関数を Excel のセルで利用します。主に利用する関数は fnWeekday です。
セルには =fnWeekday(シリアル値) を指定することで戻り値を得ることができます。
また、=fnWeekday(シリアル値, 1) のように第2引数に 1 を指定すると、平日と休日、祝日の名称のいずれかを得ることができます。
これが 2 の場合は「祝日の趣旨」(画像における D 列)を得ます。
セル内の記述例 | 出力例 | 備考 |
---|---|---|
=fnWeekday(DATE(2024,5,5)) | 8 | 祝日を示す 8 を表示する |
=fnWeekday(DATE(2024,5,5),1) | こどもの日 | 平日/休日/(祝日の名称)の、いずれかを表示する |
=fnWeekday(DATE(2024,5,5),2) | こどもの人格を重んじ、こどもの幸福をはかるとともに、母に感謝する。 | 祝日の趣旨を表示する |
(もちろん、セル内で利用することも可能です)
戻り値
戻り値は、第2引数の指定で変化します。上述したように、デフォルトで weekday 関数とほぼ同じ*1ですが、追加で 8=祝日としています。
以下、第2引数を明記した場合の挙動を記載します。
0の場合:数値(デフォルト)
第2引数に 0 を指定した(もしくは指定しない)場合に出力される番号です。番号 | 内部変数 | 意味 | 備考 |
---|---|---|---|
1 | vbSunday | 日曜日 | |
2 | vbMonday | 月曜日 | |
3 | vbTuesday | 火曜日 | |
4 | vbWednesday | 水曜日 | |
5 | vbThursday | 木曜日 | |
6 | vbFriday | 金曜日 | |
7 | vbSaturday | 土曜日 | |
8 | - | 祝日 |
1 の場合:名称
第2引数に 1 を指定した場合に出力される文字列です。文字列 | 意味 | 備考 |
---|---|---|
休日 | 土日どちらか | |
平日 | 土日祝以外の平日(実際は月~金曜日) | |
(各祝日名) | 祝日 |
2 の場合:趣旨
第2引数に 2 を指定した場合に出力される文字列です。趣旨 | 意味 | 備考 |
---|---|---|
(Nothing) | 平日/休日であり、祝日ではない日 | |
(各祝日の趣旨) | 法律などで定義される趣旨 |
関数
作成したモジュールは、つぎの五つの関数から成り立っています。fnWeekday(Serial, [Switch])
このモジュールの本丸で、公式の weekday 関数のように使います。戻り値として曜日(vbMonday から vbSaturday)だけでなく、追加で Holiday を意味する 8 も返します。
オプションには、シリアル値が必要です。
戻り値の内容を変えるために、Switch 番号も指定可能です。
第2引数を指定した際に、セルに表示される内容は、次の通りです。
Switch | 意味 | 備考 |
---|---|---|
0 | 曜日と祝日を意味する 1~8 の数字を返す | Switch を省略した場合のデフォルト |
1 | 平日/休日/祝日の名称を返す | |
2 | 祝日の趣旨を返す |
fnDate(Year, Month, Day)
Excel 関数 date コマンドを模したものです。オプションには、年・月・日の、三つが必要です。
Excel VBA の場合、DateValue コマンドを使えばいいのですが、年月日を文字列で指定しなければならないため、コードがかなり読みにくくなっていました。
可読性を目的に関数化しています。
fnHappyMonday(Year, Month, Weeks)
ハッピーマンデー制度でシリアル値を取得するのに必要な、x年x月の第x月曜日、という指定でシリアル値を取得するための関数です。オプションには、年・月・第x週の、三つが必要です。
考え方としては、月の1日が何曜日なのかを見て、そこから月曜日が何日なのかを割り出します。
あとは、7日に第x週のx-1 を掛けたものを足してあげれば、シリアル値を取得できます。
fnVernalEquinox(Year)
春分の日を割り出し、シリアル値を取得するための関数です。オプションには、年の指定が必要です。
1行しかない、かなり短いコードですが関数化しています。
計算で出力した日付ではない場合、ここで出力情報を調整する予定です。
fnAutumnalEquinox(Year)
秋分の日を割り出し、シリアル値を取得するための関数です。オプションには、年の指定が必要です。
1行しかない、かなり短いコードですが関数化しています。
計算で出力した日付ではない場合、ここで出力情報を調整する予定です。
ソースコード
Option Explicit Public Function fnWeekday(Serial As Date, Optional Switch As Byte = 0) ' ######################################################################### ' # ' # 呼び出されると、引数の Serial から曜日/祝日情報を返すマクロ ' # デフォルトの戻り値は、以下の通り ' # ' # 戻り値の定義 ' # 0 = 平日(月曜~金曜) ' # 1 = 日曜日(vbSunday) ' # 2 = 曜日月(vbMonday) ' # 3 = 火曜日(vbTuesday) ' # 4 = 水曜日(vbWednesday) ' # 5 = 木曜日(vbThursday) ' # 6 = 金曜日(vbFriday) ' # 7 = 土曜日(vbSaturday) ' # 8 = 祝日 ' # ' ######################################################################### ' ### 変数定義 ######################### Dim DEFpDayName As String Dim DEFpDayMeaning As String Dim pDayName As String Dim pDayMeaning As String Dim pRV As Byte Dim pYYYY As Integer Dim fSubstitute As Boolean ' ### 変数設定 ######################### DEFpDayName = "平日" DEFpDayMeaning = "(Nothing)" pDayName = DEFpDayName pDayMeaning = DEFpDayMeaning pYYYY = Year(Serial) ' ### メイン処理 ####################### ' serial に指定された年月日と、該当する年の祝日に相当するシリアル値を比較する。 ' 該当の祝日であれば、第2引数通りに変数を設定する。 ' もし該当の祝日名があれば、戻り値 8 を指定する。 Select Case Serial ' 日付が固定されているもの Case fnDate(pYYYY, 1, 1) pDayName = "元旦" pDayMeaning = "年のはじめを祝う。" Case fnDate(pYYYY, 1, 15) If pYYYY <= 1999 Then pDayName = "成人の日" pDayMeaning = "おとなになったことを自覚し、みずから生き抜こうとする青年を祝い、励ます。" End If Case fnDate(pYYYY, 2, 11) pDayName = "建国記念の日" pDayMeaning = "建国をしのび、国を愛する心を養う。" Case fnDate(pYYYY, 2, 23) If 2019 < pYYYY Then pDayName = "天皇誕生日" pDayMeaning = "天皇の誕生日を祝う。" End If Case fnDate(pYYYY, 4, 29) If 2007 <= pYYYY Then pDayName = "昭和の日" pDayMeaning = "激動の日々を経て、復興を遂げた昭和の時代を顧み、国の将来に思いをいたす。" ElseIf 1989 <= pYYYY Then pDayName = "みどりの日" pDayMeaning = "自然の恩恵に感謝する" ElseIf 1948 <= pYYYY Then pDayName = "天皇誕生日" pDayMeaning = "天皇の誕生を祝う(昭和天皇)" ElseIf 1927 <= pYYYY Then pDayName = "天長節" pDayMeaning = "天地が永久であるように天皇の治世も続くように" End If Case fnDate(pYYYY, 5, 3) pDayName = "憲法記念日" pDayMeaning = "日本国憲法の施行を記念し、国の成長を期する。" Case fnDate(pYYYY, 5, 4) If 2007 <= pYYYY Then pDayName = "みどりの日" pDayMeaning = "自然に親しむとともにその恩恵に感謝し、豊かな心をはぐくむ。" End If Case fnDate(pYYYY, 5, 5) pDayName = "こどもの日" pDayMeaning = "こどもの人格を重んじ、こどもの幸福をはかるとともに、母に感謝する。" Case fnDate(pYYYY, 7, 20) If pYYYY <= 2002 Then pDayName = "海の日" pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。" End If Case fnDate(pYYYY, 8, 11) ' 2014年制定、2016年より施工 If 2016 <= pYYYY Then pDayName = "山の日" pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。" End If Case fnDate(pYYYY, 9, 15) If pYYYY <= 2002 Then pDayName = "敬老の日" pDayMeaning = "多年にわたり社会につくしてきた老人を敬愛し、長寿を祝う。" End If Case fnDate(pYYYY, 11, 3) pDayName = "文化の日" pDayMeaning = "自由と平和を愛し、文化をすすめる。" Case fnDate(pYYYY, 11, 23) pDayName = "勤労感謝の日" pDayMeaning = "勤労をたっとび、生産を祝い、国民たがいに感謝しあう。" Case fnDate(pYYYY, 12, 23) If pYYYY < 2019 Then ' 以降、上皇陛下 pDayName = "天皇誕生日" pDayMeaning = "天皇の誕生日を祝う。" End If End Select Select Case Serial ' ハッピーマンデー Case fnHappyMonday(pYYYY, 1, 2) ' 2000 年より適用 If 2000 <= pYYYY Then pDayName = "成人の日" pDayMeaning = "おとなになったことを自覚し、みずから生き抜こうとする青年を祝いはげます。" End If Case fnHappyMonday(pYYYY, 7, 3) If 2003 <= pYYYY Then ' 2003 年より適用 pDayName = "海の日" pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。" End If Case fnHappyMonday(pYYYY, 9, 3) If 2003 <= pYYYY Then pDayName = "敬老の日" pDayMeaning = "多年にわたり社会につくしてきた老人を敬愛し、長寿を祝う。" End If Case fnHappyMonday(pYYYY, 10, 2) ' 2000 年より適用。2020 年より名称変更 If 2020 <= pYYYY Then pDayName = "スポーツの日" pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。" ElseIf 2000 <= pYYYY Then pDayName = "体育の日" pDayMeaning = "スポーツにしたしみ、健康な心身をつちかう日" End If ' 春分/秋分の日 Case fnVernalEquinox(pYYYY) pDayName = "春分の日" pDayMeaning = "自然をたたえ、生物をいつくしむ。" Case fnAutumnalEquinox(pYYYY) pDayName = "秋分の日" pDayMeaning = "祖先をうやまい、なくなった人々をしのぶ。" End Select ' 天皇の即位の日及び即位礼正殿の儀の行われる日を休日とする法律 Select Case Serial Case fnDate(2019, 5, 1) pDayName = "天皇の即位の日" Case fnDate(2019, 5, 2) pDayName = "国民の休日" Case fnDate(2019, 10, 22) pDayName = "即位礼正殿の儀の行われる日" End Select ' 振替休日 Select Case Serial Case fnDate(pYYYY, 1, 1) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 2, 11) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 2, 23) + 1 If 2019 < pYYYY Then If Weekday(Serial) = vbMonday Then fSubstitute = True End If Case fnDate(pYYYY, 4, 29) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 5, 5) + 1 ' 5月5日が日曜~火曜日だったら、5/6 が振替休日 If vbSunday <= Weekday(fnDate(pYYYY, 5, 5)) And Weekday(fnDate(pYYYY, 5, 5)) <= vbTuesday Then fSubstitute = True End If Case fnDate(pYYYY, 8, 11) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 11, 3) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 11, 23) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnDate(pYYYY, 12, 23) + 1 If pYYYY < 2019 Then ' 以降、上皇陛下 If Weekday(Serial) = vbMonday Then fSubstitute = True End If ' ハッピーマンデー Case fnHappyMonday(pYYYY, 1, 2) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnHappyMonday(pYYYY, 7, 3) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnHappyMonday(pYYYY, 9, 3) + 1 ' シルバーウィーク対応 ' もし、敬老の日の2日後が秋分の日なら、国民の休日にする。 If fnHappyMonday(pYYYY, 9, 3) + 2 = fnAutumnalEquinox(pYYYY) Then pDayName = "国民の休日" ElseIf Weekday(Serial) = vbMonday Then fSubstitute = True End If Case fnHappyMonday(pYYYY, 10, 2) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True ' 春分/秋分の日 Case fnVernalEquinox(pYYYY) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True Case fnAutumnalEquinox(pYYYY) + 1 If Weekday(Serial) = vbMonday Then fSubstitute = True 'Case DateValue("2020/9/22") ' DayName = "秋分の日" End Select If fSubstitute = True Then pDayName = "振替休日" ' ----------------------------------------------------------- ' 令和 2 年(2020年)及び令和 3 年(2021年)に限り、 ' 東京オリンピック・パラリンピック競技大会の開催にあわせ、 ' 「海の日」、「スポーツの日」及び「山の日」が移動している。 ' ----------------------------------------------------------- ' 令和2年 (2020) & 令和3年 (2021) Select Case Serial ' 海の日 Case fnHappyMonday(2020, 7, 3), fnHappyMonday(2021, 7, 3) pDayName = DEFpDayName pDayMeaning = DEFpDayMeaning Case fnDate(2020, 7, 23) pDayName = "海の日" pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。" Case fnDate(2021, 7, 22) pDayName = "海の日" pDayMeaning = "海の恩恵に感謝するとともに、海洋国日本の繁栄を願う。" ' スポーツの日 Case fnHappyMonday(2020, 10, 2), fnHappyMonday(2021, 10, 2) pDayName = DEFpDayName pDayMeaning = DEFpDayMeaning Case fnDate(2020, 7, 24) pDayName = "スポーツの日" pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。" Case fnDate(2021, 7, 23) pDayName = "スポーツの日" pDayMeaning = "スポーツを楽しみ、他者を尊重する精神を培うとともに、健康で活力ある社会の実現を願う。" ' 山の日 Case fnDate(2020, 8, 11), fnDate(2021, 8, 11) pDayName = DEFpDayName pDayMeaning = DEFpDayMeaning Case fnDate(2020, 8, 10) pDayName = "山の日" pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。" Case fnDate(2021, 8, 8) pDayName = "山の日" pDayMeaning = "山に親しむ機会を得て、山の恩恵に感謝する。" End Select ' 祝日値判定 If pDayName = DEFpDayName Then ' 平日/休日であれば、戻り値を 1~7 で指定する。 ' ## 曜日選択 ##### If IsDate(Serial) Then Select Case Weekday(Serial) Case vbSunday pRV = vbSunday pDayName = "休日" Case vbMonday pRV = vbMonday Case vbTuesday pRV = vbTuesday Case vbWednesday pRV = vbWednesday Case vbThursday pRV = vbThursday Case vbFriday pRV = vbFriday Case vbSaturday pRV = vbSaturday pDayName = "休日" End Select Else ' IsDate の判定内容にエラーがある場合 fnWeekday = "祝日値判定エラー" Exit Function End If Else ' 平日でなければ、戻り値を 8 で指定する。 pRV = 8 End If ' ### 終了処理 ######################### ' オプションの内容で、戻り値を変更する。 Select Case Switch Case 0 fnWeekday = pRV Case 1 fnWeekday = pDayName Case 2 fnWeekday = pDayMeaning End Select ' ###################################### End Function Public Function fnDate(Year, Month, Day) ' ######################################################################### ' # ' # VBA の date 関数は、Excel sheet の date 関数と異なり、文字列を指定する。 ' # この関数は、セルで利用する date 関数と同じ使い勝手を実現するもの。 ' # ' ######################################################################### fnDate = DateValue(Year & "/" & Month & "/" & Day) End Function Public Function fnHappyMonday(Year, Month, Weeks) ' ######################################################################### ' # ' # ハッピーマンデー用のシリアル値を返す。 ' # 指定された、Year 年 Month 月の第 Weeks 週の月曜日(シリアル値)を返す。 ' # ' # 参考資料 ' # http://www.relief.jp/itnote/archives/003241.php ' ######################################################################### Dim pMondayDate As Byte Dim pFirstMonDay As Date ' ## 第1週目の月曜日を求める。 ' 先に指定月の1日が何曜日なのかを見て、次の月曜日が何日なのかを指定する。 Select Case Weekday(fnDate(Year, Month, 1)) Case vbSunday ' 1 ' x月1日が日曜日なら、月曜日は翌日の 2 日 pMondayDate = 2 Case vbMonday ' 2 ' x月1日が月曜日なので、そのまま 1 日 pMondayDate = 1 Case vbTuesday ' 3 ' x月1日が火曜日なので、月曜日は 6 日後の 7 日 pMondayDate = 7 Case vbWednesday ' 4 ' x月1日が水曜日なので、月曜日は 5 日後の 6 日 pMondayDate = 6 Case vbThursday ' 5 pMondayDate = 5 Case vbFriday ' 6 pMondayDate = 4 Case vbSaturday ' 7 pMondayDate = 3 End Select ' 第1週目の月曜日から何週間後なのか、必要な日数を足してシリアル値を返す。 fnHappyMonday = fnDate(Year, Month, pMondayDate) + (7 * (Weeks - 1)) End Function Public Function fnVernalEquinox(Year) ' ######################################################################### ' # ' # 呼び出されると、引数の Year から算出した 春分の日 情報を返すマクロ ' # ' # 参考 URL http://www.wanichan.com/pc/excel/2010/5/page07.html ' ######################################################################### fnVernalEquinox = fnDate(Year, 3, Int(20.8431 + 0.242194 * (Year - 1980) - Int((Year - 1980) / 4))) End Function Public Function fnAutumnalEquinox(Year) ' ######################################################################### ' # ' # 呼び出されると、引数の Year から算出した 秋分の日 情報を返すマクロ ' # ' # 参考 URL http://www.wanichan.com/pc/excel/2010/5/page07.html ' ######################################################################### fnAutumnalEquinox = fnDate(Year, 9, Int(23.2488 + 0.242194 * (Year - 1980) - Int((Year - 1980) / 4))) End Function
その他
zip ファイル
コピペより、インポート可能なファイルが良いという方向け。現在バージョン
過去バージョン
更新履歴
参考サイト様
- 国民の祝日に関する法律 | e-Gov法令検索
- http://www.relief.jp/itnote/archives/003241.php
- →リダイレクト先 成人の日(1月の第2月曜日)を求める−WEEKDAY関数・DATE関数:Excel(エクセル)の関数・数式の使い方/日付の処理・計算
- Excel 2010:春分の日や秋分の日を求めるには