AddinBox(Title_Logo)

  -- Page 1 --

      VBAおよびVB用の祝日判定用マクロ[関数](『kt関数アドイン/kt祝日名取得』の
  ロジックと同じものです)を公開しています。また、VBA用の祝日判定用マクロ[関数]を
  基にして、他言語向けに編集移植したコードを頂きましたので、併せて、このページで
  公開します。

      なお、祝日に関する詳細情報こちらのページをご覧下さい。

      VBA用コードは純粋にVB構文だけ(エクセル独自の機能は使ってません)で作って
    ありますので、エクセルだけでなくアクセスや、その他のVBAを使うアプリケーション
    でも利用できます。
  ※ 重要 ※
    ・ [ 2019年 臨時休日 ]  (2018/12/8)
      即位日(5/1) & 即位礼正殿の儀(10/22) の 改正祝日法が成立しました
      ドミノ で 退位日(4/30) を含めてGWは10連休になります。
      判定ロジック の修正方針は こちら を参照してください。

    ・ [ 東京五輪 臨時祝日 / 体育の日 改名 ]  (2018/6/21)
      「体育の日」が2020年から「スポーツの日」に改名となります。
      東京五輪特措法により2020年の「海の日/山の日/スポーツの日」が移動となります。

    ・ [ 生前退位/皇位継承 ]  (2018/2/15)
      平成31年 ( 2019年 ) 4月30日 退位 / 翌5月1日 即位 で決定しました。
      天皇誕生日が [ 12/23 ⇒ 2/3 ] へ変わります(2019年に 天皇誕生日はありません)。
      また、[ 即位礼 正殿の儀 ] は10月22日です。



※VBA以外に移植したコードも紹介しています※
 ・ 「2019年の即位に伴う 臨時祝日」 改正への対応済みです。 (2018/12/8)
 ・ 「東京五輪 臨時祝日/体育の日 改名」 改正への対応済みです。 (2018/6/21)
 ・ 「天皇誕生日の変更」 改正への対応済みです。 (2018/2/15)

   [ 旧サイト ( DIONサーバー ) の Internet Archive ( Page 1 ) ]
--言語-- -- 移  植 -- -公開日- -頁-
  ・ 祝日判定マクロ の 設計方針について
  ・ And / Or 演算子 : 完全評価( Complete )型 と 短絡評価( Short-circuit )型
  ・ オーソドックス な 「表引き」 手法との比較
  ・ 祝日判定の拡張 ( 土日も含める 等 ) について
  ・ 拡張マクロ : 銀行休日の判定
  ・ 5月6日 ( 振替休日 ) の判定方法について
  ・ 2019年GWの休日(4/30,5/1,5/2) の判定方法について
  ・ ( 番外 ) 新元号対応 日付変換関数 EraFormat / EraCDate
 
1
VB/VBA AddinBox(角田) 2002/ 3/16 1
Delphi AddinBox(角田) 2002/11/22
JavaScript AddinBox(角田) 2003/ 5/ 9
OOoBasic AddinBox(角田) 2005/ 4/15

VB2005 Fukuchi さん 2006/ 7/ 4 2
VBS 立野 徹 さん 2003/ 3/ 2
PHP 代理店どっとこむ「中野」 さん 2003/ 5/ 6

C こほろぎ AsaPi! さん 2003/ 3/ 2 3
C# 小山 隆史 さん 2005/12/17
Perl 富士ソフトサービスビューロ(株)
    BS部 「稲葉」 さん
2003/ 6/ 9
AWK 富士ソフトサービスビューロ(株)
    BS部 「稲葉」 さん
2003/ 6/11

Apollo たけ(tk) さん 2003/ 9/24 4
Ruby たけ(tk) さん 2005/ 4/15
JAVA 阿蛭 栄一 さん 2003/12/21

Transact-SQL シリコンブレス  有方 公一 さん 2006/ 8/ 1 5
PL/SQL 菅 康明 さん 2006/12/ 1
Python 瀬戸口 光宏 さん 2007/ 5/28

ActionScript 3 stocksrc.com  2010/ 3/23 6
Go 言語 杉田 臣輔 さん 2015/ 1/ 6
       
      自由に各自のマクロに組み込んで利用して下さい。なお、フリー/シェアソフト
    開発での利用も可(フリー/シェアでの利用の場合、事後で結構ですので一言
    お知らせください)です。ただし、引用に当たっては、マクロの先頭に記述してある
        コメント(CopyRight )を必ず一緒に引用する事

    を条件とします。

      なお、
          他サイト上で本マクロを直接引用(マクロ全体を丸々貼り付ける等)
    する事は、ご遠慮願います。本ページへのリンクによる紹介で対応して下さい。

      [ktHolidayName]という関数名そのものは、各自の環境における命名規則に沿って
    変更しても構いません
      VBA(VB含む)で利用する場合はマクロのコード構成を一切変更しないでください。
    VBAというレスポンス的に不利な言語でも出来る限りレスポンスを良くする事を前提に
    設計してある為、コード内容を変更するとレスポンスが低下する可能性があります

      VBA以外の言語に移植する場合は、その言語の特性に合わせたベストなコード構成に
    変更しても構いません。

    また、出来上がったものをご連絡頂ければ、このページにて紹介させて貰います。

    尚、移植に際しては、And/Orによる条件演算、および[春分の日/秋分の日]算出式の
    INT演算について各言語特性に留意して下さい。また、表引き手法を採らない理由
    御一読ください。

[ この場所へのリンク ]
  このロジックは、営業日数計算など連続して祝日判定を行なう処理の為に、レスポンス
を第一義
として、可能な限り少ない【条件判定の実行】で結果を出せるように設計して
あります(このコードはVBAでの利用を前提にして作っています。同じコードでも、VBでネ
イティブコンパイルした場合と比べれば、VBAは、かなり低速です。そのVBAを使ってい
ても、出来るだけ効率良く高速に処理されるように作ってあります)。

  1年間の判定を考えた場合、1年365日の内、祝日は20日ほど、残りの345日ほどは
祝日以外
です。したがって、レスポンスを向上させるポイントは『如何に祝日と判定するか』
ではなく、『どれだけ早く祝日でないという判断を下せるか』です。

  And条件を使わずに「If文のネスト」にしているのは、この為です。また、一番最初に『月』
による振り分けを行なっている(Select  Case文)ので、例えば6月の日付に対して、1月とか
9月とか他の月の条件判定まで実行してしまう事もありません。

  本ロジックは
      「1年間のスパンを持つ期間に対する営業日数計算」を1000件連続処理
というシナリオを基準にして、その状況においてもレスポンス的にストレスなく実行できるように
設計しています。 1年間ですから、データ1件に対して祝日判定が365回必要です。それが
1000件ですので、36万5千回 の連続実行という事になります。


[ この場所へのリンク ]
(補) And / Or 演算子 : 完全評価 ( Complete ) 型 と 短絡評価 ( Short-circuit ) 型
        And / Or 演算子で繋いだ論理演算には 完全評価 ( Complete ) 型短絡評価 ( Short-circuit ) 型 があり、
        それはコンピュータ言語によって異なります。短絡評価型か 否か を調べるには、このようなテスト を実行すれば
        確認できます。
            -- 完全評価 ( Complete ) 型 --
                式の途中で結果が決まるような条件であっても、式の最後まで比較演算を実行します。
            -- 短絡評価 ( Short-circuit ) 型 --
                And 演算 … 左辺が False ならば、右辺は評価せずに False で決定します。
                Or 演算   … 左辺が True ならば、右辺は評価せずに Trueで決定します。

        VB ( VBA ) は完全評価 ( Complete ) 型の言語であり、必要の無い判定をスキップさせるには And / Or を
        使わず、 IF 文を分割してネストさせる必要があります。
        逆に、短絡評価 ( Short-circuit ) 型の言語ならば、And / Or を使って条件式をスッキリさせるコーディング
        を行なうことが可能です。

[ この場所へのリンク ]
※ オーソドックスな「表引き」手法との比較 ※
  祝日判定処理で従来(現在も)最も使われている手法は『予め祝日の日付をテーブルに用意しておいて、その日付と比較/検索する』というものでしょう。

  本ロジックは個々の祝日条件をひとつひとつ判定するように作られていますので、ステップ数としては多くなります。 対して「表引き」の場合にはテーブルからの比較/検索で済ませますから、言語の特徴によって、その部分は1〜数ステップで済む筈です。 そうすると、一見、プログラムの大きさから、「表引き」の方が効率的で速いように思えてしまいます。しかし、実際に両者を実行してみると、本ロジックの方が断然速い事が判るでしょう。

  何故かというと、プログラムの実行に要する時間は、コーディングされたステップ数の大小によるのではなく、実行の際に処理されるステップ数の大小による からです。

--- 本ロジック の特徴 ---
  前述のように
    ・ And 条件を使わずに 「 If 文のネスト」 にしている。
    ・ 一番最初に『月』による振り分けを行なっている。
      これにより、6月の日付に対して、1月とか9月とか他の月の条件判定まで実行する事がない。
という特徴で設計してあります。
  コーディングステップ数は多くても、個々の日付を判定する際に実行されるステップ数は少ないです。更に、平日なら尚更少ない実行ステップで完了します。データ量の9割以上を占めるであろう平日データに対してより速く完了するという事は、データ量が増えれば増える程、より効果を発揮します。また、どの月の日付なら速い/遅いといった事もありませんから、日付の偏りによるパフォーマンスの上下もありません。

  また、プログラムコード だけですから 「外部データの取り込み」 等に時間を要する事もありません

--- 表引き の特徴 ---
  普通、「祝日」のみのテーブルを用意しますので、判定するにはテーブル内の日付と順々に比較する必要があります。表引きには順次検索/二分検索といった比較方法があり、更に順次検索では「総当り」 か 「大小判定を加えてテーブルの途中で終了」 の2つがありえます。どういった方法が採られるかは配列の言語特性やロジックの作り方によるでしょう。
  1年間の祝日をテーブルに用意するならば、20数件ですから、
      ・ 二分検索では毎回3〜4回
      ・ 順次検索の場合、
         ・ 総当りなら毎回20数回(全部見ないと該当日付無しかが判らない)
         ・ 大小比較付きなら平均10回
の比較処理が実行される事となります。大小比較の場合、日付によって二分検索並みに数回で終わる事も、総当りのように20数回掛かる事もありますので、日付の偏りによってはパフォーマンスが非常に上下する事が想像できます。
  言語仕様によっては「処理する日付をキーとしてテーブルに渡して結果を得る」 という検索メソッドの1ステップのコーディングで済んでいる場合もあるでしょうが、言語側の内部では上記と同様のことが実行されていますので、1ステップだから速いという事はありません。
  また、1年分ではなく2年分とか数年分といった長期の祝日データを用意すればする程、比較回数は増えてしまいます。特に重要なのは、この比較回数が 祝日/平日に関係なく同じように掛かってしまう事です。例え、平日だけのデータを処理する場合であっても、祝日データが含まれている時よりも早く完了する事は期待できません。

  また、「表」 が データベース 等の外部データの場合、その DB 等の ロード 時間も当然出て来ます。 システム が立ち上がる初期化の際の1回のみで、後はず〜っと オンメモリ ならば速度的に支障はないでしょうが、祝日判定を行なう度に ( 日付 1つ1つ に毎回 ) ロード処理があるならば、速度的にはかなり不利となるでしょう。

  尚、これらの速度的に有利/不利というのは、大量のデータを処理するケースを考えたものです(本ロジックでは [1年間というスパンの営業日数計算を要するデータが1000件] というケースを想定して設計してあります。つまり、祝日判定を36万回連続実行)。
  しかし、カレンダーの1ヶ月分のレイアウトを作成するというケースでは「日付が限られた範囲で連続で少量」という点から、表引き手法を用いた祝日判定を用いても何ら問題は無いでしょう。

PS : 「表引き」でも非常に高速で処理する手法はあります。
  1年間(365 or 366日分)のテーブルを用意(2年間分なら730 or 731日分)し、1月1日からの通算日を『添字』として各要素に平日/祝日のフラグ、もしくは空文字/祝日名を格納しておきます。処理する日付についても同様に「1月1日からの通算日」に変換し、それを添字としてテーブル内容を取得すれば、毎回1回の比較処理で完了となります。当然、本ロジックよりも速いでしょう。kt関数アドインでは、この手法を使って、より高速化を図っています(年間テーブルの作成には本ロジックを使用しています)。


[ この場所へのリンク ]

[ Note ]
  Access などで、[Null値]を受け取る/返すといった必要がある場合には、下記のように
『ktHolidayName 』の外側に、もうひとつ関数を被せるようにする事で『ktHolidayName 』
自体は変更せずに利用する事ができます(この場合には、ktHolidayName は'Private'に
して下さい)。

Public Function 祝日名(ByVal 日付 As Variant) As Variant
    If IsDate(日付) Then
        祝日名 = ktHolidayName(CDate(日付))
    Else
        祝日名 = Null
    End If
End Function

  その他に「銀行休日」で「土日休み」部分も一緒にフォローしたいといった場合でも
同様の方法で対応できます。

Public Function 祝日_土日(ByVal 日付 As Date) As String
    祝日_土日 = ktHolidayName(日付)
    If (祝日_土日 = "") Then
        Select Case Weekday(日付)
            Case vbSunday: 祝日_土日 = "日"
            Case vbSaturday: 祝日_土日 = "土"
            Case Else
        End Select
    End If
End Function

  このようにする事で[ktHolidayName]のロジック自体を変更せずに、様々な条件を付け加える
事が可能です。引用する際には[ktHolidayName]そのものには手を加えずに、コメントを含めて
丸々コピーするようにしてください。
  ktHolidayName/prv祝日 の内部に処理を追加してしまうと、将来再び祝日法が変更された
場合に、新しいktHolidayName/prv祝日上書き修正により、追加した処理が消えてしま
います。そうならない為にも、ktHolidayName/prv祝日には手を加えずに、その外側にプロシ
ジャーを用意して、そこで機能追加を施すようにして下さい。

[ この場所へのリンク ]
  MOUG(Access 初級) で回答したので、ここにも載せておきます。  (2004/9/13 追記)

 ※※ 訂正案内 ※※    ( 2016/3/5 )
    ここで紹介している応用例の Bank_Networkdays 関数に誤りがありました
    If 文の True/False を取り違えていたため、営業日数 ではなく、[休業]日数 を算出する ロジック となっていました。



  『銀行休日』にするには更に下記のコードを加えると、渡した日付に対して
  「銀行休日か否か」が[True/False ]で得られます。

Public Function Bank_Holiday (ByVal 日付 As Date) As Boolean
  If (ktHolidayName (日付) <> "") Then
    Bank_Holiday = True    '祝日
  Else
    Select Case Weekday(日付)
      Case vbSunday
        Bank_Holiday = True
      Case vbSaturday
        Bank_Holiday = True
      Case Else
        Select Case Format(日付, "mmdd")
          Case "0102": Bank_Holiday = True  '年始
          Case "0103": Bank_Holiday = True  '年始
          Case "1231": Bank_Holiday = True  '大晦日
          Case Else
            Bank_Holiday = False
        End Select
    End Select
  End If
End Function

  銀行休日ベースで営業日を算出するには、更に下記のコードを加えれば、
  日付と日数に応じた営業日が出て来ます。[日数=0]の場合には、休日で
  あっても[日付]がそのまま返ります(WORKDAY と同じ)。
  ある日付に対する休日前営/休日翌営の求め方(WORKDAY と同じ)。
      休日前営: =Bank_Workday(日付+1, -1)
      休日翌営: =Bank_Workday(日付-1, 1)

Public Function Bank_Workday (ByVal 日付 As Date, ByVal 日数 As Integer) As Date
Dim i As Integer
Dim wkStep As Integer
Dim wkDate As Date
  If (日数 = 0) Then
    Bank_Workday = 日付
    Exit Function
  ElseIf (日数 > 0) Then
    wkStep = 1
  Else
    wkStep = -1
  End If
 
  i = 0
  wkDate = 日付
  Do
    wkDate = wkDate + wkStep
    If (Bank_Holiday (wkDate) = False) Then
      i = i + wkStep
    End If
  Loop Until (i = 日数)
  Bank_Workday = wkDate
End Function

-- 算出例 (分析ツールの WORKDAY関数と同じです) --
    〔日数=   1〕 …… 「日付」の翌営業日
    〔日数=−1〕 …… 「日付」の前営業日
    〔日数=   0〕 …… 「日付」の当日(休業日でも)


  営業日数なら下記の関数になります。(2005/2/15 追記)

  ( 訂正案内  2016/3/5 )
      If 文の True/False を取り違えていたため、営業日数 ではなく、[休業]日数 を算出する ロジック となっていました。


Public Function Bank_Networkdays (ByVal 開始日 As Date, ByVal 終了日 As Date) As Integer
Dim wkDate As Date
Dim wkStep As Integer
Dim int日数 As Integer
  if (開始日 <= 終了日) Then
    wkStep = 1
  Else
    wkStep = -1
  End If
  int日数 = 0
  For wkDate = 開始日  To 終了日  Step wkStep
    If (Bank_Holiday (wkDate) = False) Then  '2016/3/5 修正 (誤)True⇒(正)False
      int日数 = int日数 + wkStep
    End If
  Next wkDate
  Bank_Networkdays = int日数
End Function

-- 算出例 (分析ツールの NETWORKDAYS関数と同じです) --
    〔終了日=開始日         〕 …… 1(開始日が休業日の場合は 0 )
    〔終了日=開始日の翌営〕 …… 2(開始日が休業日の場合は 1 )
    〔終了日=開始日の前営〕 …… −2(開始日が休業日の場合は −1 )


[ この場所へのリンク ]

VB/VBA 用祝日判定コード 】    [ 検証用データ ( 祝日一覧 ) は JavaScript 版による ツール で取得できます ]  [ 不具合報告 メール送信 ]
  2005/5/20 [昭和の日] 改正の修正
  2014/ 5/29 [山の日] 改正の修正
  2018/ 2/15 [天皇誕生日の変更] 改正の修正
  2018/ 6/21 [体育の日⇒スポーツの日 改名] & [五輪特措法による祝日移動] 改正の修正
  2018/12/8 [即位の日 および 4/30 & 5/2の国民の休日] [即位礼正殿の儀] 改正の修正

    土日なども一緒に判定するなど条件を付加する場合は、こちらの解説を参考にして下さい。
    Access で「Excel のWorkday/NetWorkdays 関数」と同義のものを組み込む場合はこちら
    『祝日について

    「昭和の日」に伴う「振替休日(5月6日)」改正への修正方針もお読みください。

    「即位の日(2019/5/1)」に伴う「祝日に挟まれた平日(4/30 & 5/2)の休日化」への修正方針もお読みください。
    ( 番外 ) 「即位」絡みで新元号対応のサポート対象外の環境向け新元号対応変換関数 EraFormat を作成しました(VBA/VB6 で利用可能)。

    下記マクロのコメントに記載してある利用規約(*2)の遵守にご協力ください。
    Q&Aサイト等での回答に本コードを丸々全部貼り付ける事はお止めください。
    特に、先頭のコメント(作者情報/利用規約)を削ってマクロ部分のみ貼り付ける事(*1への違反)はお止めください。



    ----------- VB / VBA における 曜日値について -----------
        曜日の値は [ 日(1), 月(2), 火(3), 水(4), 木(5), 金(6), 土(7) ] です。
        システム定数の [ vbSunday, vbMonday, … vbSaturday ] が利用できます。

----------------------------------------------------------------------------------------

 

'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
'_/
'_/  --- VB / VBA 版 ( Update: 2018/12/8 ) ---
'_/
'_/  CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
'_/  ( AddinBox  http://addinbox.sakura.ne.jp/index.htm )
'_/  (  旧サイト  http://www.h3.dion.ne.jp/~sakatsu/index.htm )
'_/
'_/    この祝日マクロは『kt関数アドイン』で使用しているものです。
'_/    このロジックは、レスポンスを第一義として、可能な限り少ない
'_/    【条件判定の実行】で結果を出せるように設計してあります。
'_/
'_/    この関数では以下の祝日変更までサポートしています。
'_/    (a) 2019年施行の「天皇誕生日の変更」 12/23⇒2/23 (補:2019年には[天皇誕生日]はありません)
'_/    (b) 2019年の徳仁親王の即位日(5/1) および
'_/       祝日に挟まれて「国民の休日」となる 4/30(平成天皇の退位日) & 5/2 の2休日
'_/    (c) 2019年の「即位の礼 正殿の儀 (10/22) 」
'_/    (d) 2020年施行の「体育の日の改名」⇒スポーツの日
'_/    (e) 五輪特措法による2020年の「祝日移動」
'_/       海の日:7/20(3rd Mon)⇒7/23, スポーツの日:10/12(2nd Mon)⇒7/24, 山の日:8/11⇒8/10
'_/
'_/  (*1)このマクロを引用するに当たっては、必ずこのコメントも
'_/      一緒に引用する事とします。
'_/  (*2)他サイト上で本マクロを直接引用する事は、ご遠慮願います。
'_/      【 http://addinbox.sakura.ne.jp/holiday_logic.htm 】
'_/      へのリンクによる紹介で対応して下さい。
'_/  (*3)[ktHolidayName]という関数名そのものは、各自の環境に
'_/      おける命名規則に沿って変更しても構いません。
'_/
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


Public Function ktHolidayName(ByVal 日付 As Date) As String
Dim dtm日付 As Date
Dim str祝日名 As String
Const cst振替休日施行日 As Date = "1973/4/12"

'時刻/時刻誤差の削除(Now関数などへの対応)
    dtm日付 = DateSerial(Year(日付), Month(日付), Day(日付))

    'シリアル値は[±0.5秒]の誤差範囲で認識されます。2002/6/21はシリアル値で
    '[37428.0]ですが、これに[-0.5秒]の誤差が入れば[37427.9999942130]となり、
    'Int関数で整数部分を取り出せば[37427]で前日日付になってしまいます。
    '※ 但し、引数に指定する値が必ず【手入力した日付】等で、時刻や時刻誤差を
    '  考慮しなくても良いならば、このステップは不要です。引数[日付]をそのまま
    '  使用しても問題ありません(ほとんどの利用形態ではこちらでしょうが‥‥)。


    str祝日名 = prv祝日(dtm日付)

    ' ----- 振替休日の判定 (振替休日施行日:1973/4/12) -----
    ' [ 対象日≠祝日/休日 & 対象日=月曜日 ]のみ、前日(=日曜日)を祝日判定する。
    ' 前日(=日曜日)が祝日の場合は”振替休日”となる。
    ' 尚、5月6日の扱いを
    '     「火曜 or 水曜(みどりの日(5/4) or 憲法記念日(5/3)の振替休日)」⇒5月ブロック内で判定済
    '     「月曜(こどもの日(5/5)の振替休日」⇒ここの判定処理で判定
    ' とする事により、ここでの判定対象は『対象日が月曜日』のみ となります。

    If (str祝日名 = "") Then
        If (Weekday(dtm日付) = vbMonday) Then
            If (dtm日付 >= cst振替休日施行日) Then
                str祝日名 = prv祝日(dtm日付 - 1)
                If (str祝日名 <> "") Then
                    ktHolidayName = "振替休日"
                Else
                    ktHolidayName = ""
                End If
            Else
                ktHolidayName = ""
            End If
        Else
            ktHolidayName = ""
        End If
    Else
        ktHolidayName = str祝日名
    End If
End Function

'========================================================================
Private Function prv祝日(ByVal 日付 As Date) As String
Dim int年 As Integer
Dim int月 As Integer
Dim int日 As Integer
Dim int秋分日 As Integer
Dim str第N曜日 As String
' 時刻データ(小数部)は取り除いてあるので、下記の日付との比較はOK
Const cst祝日法施行 As Date = "1948/7/20"
Const cst昭和天皇の大喪の礼 As Date = "1989/2/24"
Const cst明仁親王の結婚の儀 As Date = "1959/4/10"
Const cst徳仁親王の結婚の儀 As Date = "1993/6/9"
Const cst即位礼正殿の儀 As Date = "1990/11/12"    '平成天皇

Const cst平成天皇の退位 As Date = "2019/4/30"    '祝日ではなく「国民の休日」です
Const cst徳仁親王の即位 As Date = "2019/5/1"
Const cst2019GW国民の休日 As Date = "2019/5/2"    '祝日ではなく「国民の休日」です
Const cst即位礼正殿の儀_徳仁親王 As Date = "2019/10/22"

    int年 = Year(日付)
    int月 = Month(日付)
    int日 = Day(日付)

    prv祝日 = ""
    If (日付 < cst祝日法施行) Then
        Exit Function    ' 祝日法施行以前
    End If

    Select Case int月
    '-- 1月 --
    Case 1
        If (int日 = 1) Then
            prv祝日 = "元日"
        Else
            If (int年 >= 2000) Then
                str第N曜日 = (((int日 - 1) \ 7) + 1) & Weekday(日付)
                If (str第N曜日 = "22") Then  '2nd Monday(2)
                    prv祝日 = "成人の日"
                End If
            Else
                If (int日 = 15) Then
                    prv祝日 = "成人の日"
                End If
            End If
        End If

    '-- 2月 --
    Case 2
        If (int日 = 11) Then
            If (int年 >= 1967) Then
                prv祝日 = "建国記念の日"
            End If
        ElseIf (int日 = 23) Then
            If (int年 >= 2020) Then
                prv祝日 = "天皇誕生日"
            End If
        ElseIf (日付 = cst昭和天皇の大喪の礼) Then
            prv祝日 = "昭和天皇の大喪の礼"
        End If

    '-- 3月 --
    Case 3
        If (int日 = prv春分日(int年)) Then  ' 1948〜2150以外は[99]
            prv祝日 = "春分の日"            ' が返るので、必ず≠になる
        End If

    '-- 4月 --
    Case 4
        If (int日 = 29) Then
            If (int年 >= 2007) Then
                prv祝日 = "昭和の日"
            ElseIf  (int年 >= 1989) Then
                prv祝日 = "みどりの日"
            Else
                prv祝日 = "天皇誕生日"    ' 昭和天皇
            End If
        ElseIf (日付 = cst平成天皇の退位) Then    ' 2019/4/30
            prv祝日 = "国民の休日"    '祝日に挟まれた国民の休日です
        ElseIf (日付 = cst明仁親王の結婚の儀) Then
            prv祝日 = "皇太子明仁親王の結婚の儀"
        End If

    '-- 5月 --
    Case 5
        If (int日 = 3) Then
            prv祝日 = "憲法記念日"
        ElseIf (int日 = 4) Then
            If (int年 >= 2007) Then
                prv祝日 = "みどりの日"
            ElseIf (int年 >= 1986) Then
                ' 5/4が日曜日は『只の日曜』、月曜日は『憲法記念日の振替休日』(〜2006年)
                If (Weekday(日付) > vbMonday) Then   ' 火曜 以降(火〜土)
                    prv祝日 = "国民の休日"
                End If
            End If
        ElseIf (int日 = 5) Then
            prv祝日 = "こどもの日"
        ElseIf (int日 = 6) Then
            If (int年 >= 2007) Then
                Select Case Weekday(日付)
                    Case vbTuesday, vbWednesday
                        prv祝日 = "振替休日"    ' [5/3,5/4が日曜]ケースのみ、ここで判定
                End Select
            End If
        Else
            If (int年 = 2019) Then
                If (日付 = cst徳仁親王の即位) Then    ' 2019/5/1
                    prv祝日 = "即位の日"    ' 徳仁親王
                ElseIf (日付 = cst2019GW国民の休日) Then    ' 2019/5/2
                    prv祝日 = "国民の休日"    '祝日に挟まれた国民の休日です
                End If
            End If
        End If

    '-- 6月 --
    Case 6
        If (日付 = cst徳仁親王の結婚の儀) Then
            prv祝日 = "皇太子徳仁親王の結婚の儀"
        End If

    '-- 7月 --
    Case 7
        str第N曜日 = (((int日 - 1) \ 7) + 1) & Weekday(日付)
        Select Case int年
          Case Is >= 2021
            If (str第N曜日 = "32") Then  '3rd Monday(2)
                prv祝日 = "海の日"
            End If
          Case 2020
            '2020年はオリンピック特措法により
            '「海の日」が 7/23 / 「スポーツの日」が 7/24 に移動
            Select Case int日
              Case 23
                prv祝日 = "海の日"
              Case 24
                prv祝日 = "スポーツの日"
              Case Else
            End Select
          Case Is >= 2003
            If (str第N曜日 = "32") Then  '3rd Monday(2)
                prv祝日 = "海の日"
            End If
          Case Is >= 1996
            If (int日 = 20) Then
                prv祝日 = "海の日"
            End If
          Case Else
        End Select

    '-- 8月 --
    Case 8
        Select Case int年
          Case Is >= 2021
            If (int日 = 11) Then
                prv祝日 = "山の日"
            End If
          Case 2020
            '2020年はオリンピック特措法により「山の日」が 8/10 に移動
            If (int日 = 10) Then
                prv祝日 = "山の日"
            End If
          Case Is >= 2016
            If (int日 = 11) Then
                prv祝日 = "山の日"
            End If
          Case Else
        End Select

    '-- 9月 --
    Case 9
        '第3月曜日(15〜21)と秋分日(22〜24)が重なる事はない
        int秋分日 = prv秋分日(int年)
        If (int日 = int秋分日) Then  ' 1948〜2150以外は[99]
            prv祝日 = "秋分の日"      ' が返るので、必ず≠になる
        Else
            If (int年 >= 2003) Then
                str第N曜日 = (((int日 - 1) \ 7) + 1) & Weekday(日付)
                If (str第N曜日 = "32") Then  '3rd Monday(2)
                    prv祝日 = "敬老の日"
                ElseIf (Weekday(日付) = vbTuesday) Then
                    If (int日 = (int秋分日 - 1)) Then
                        prv祝日 = "国民の休日'火曜日&[秋分日の前日]
                    End If
                End If
            ElseIf (int年 >= 1966) Then
                If (int日 = 15) Then
                    prv祝日 = "敬老の日"
                End If
            End If
        End If

    '-- 10月 --
    Case 10
        str第N曜日 = (((int日 - 1) \ 7) + 1) & Weekday(日付)
        Select Case int年
          Case Is >= 2021
            If (str第N曜日 = "22") Then  '2nd Monday(2)
                prv祝日 = "スポーツの日'2020年より改名
            End If
          Case 2020
            '2020年はオリンピック特措法により「スポーツの日」が 7/24 に移動
          Case Is >= 2000
            If (str第N曜日 = "22") Then  '2nd Monday(2)
                prv祝日 = "体育の日"
            ElseIf (日付 = cst即位礼正殿の儀_徳仁親王) Then
                prv祝日 = "即位礼正殿の儀"    ' 徳仁親王(2019/10/22)
            End If
          Case Is >= 1966
            If (int日 = 10) Then
                prv祝日 = "体育の日"
            End If
          Case Else
        End Select

    '-- 11月 --
    Case 11
        If (int日 = 3) Then
            prv祝日 = "文化の日"
        ElseIf (int日 = 23) Then
            prv祝日 = "勤労感謝の日"
        ElseIf (日付 = cst即位礼正殿の儀) Then
            prv祝日 = "即位礼正殿の儀"    ' 平成天皇
        End If

    '-- 12月 --
    Case 12
        If (int日 = 23) Then
            If ((int年 >= 1989) And (int年 <= 2018)) Then
                prv祝日 = "天皇誕生日"    ' 平成天皇
            End If
        End If
    End Select
End Function

'======================================================================
'  春分/秋分日の略算式は
'    『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』
'  で紹介されている式です。

Private Function prv春分日(ByVal 年 As Integer) As Integer
    If (年 <= 1947) Then
        prv春分日 = 99        '祝日法施行前
    ElseIf (年 <= 1979) Then
        '(年 - 1983)がマイナスになるので『Fix関数』にする
        prv春分日 = Fix(20.8357 + (0.242194 * (年 - 1980)) - Fix((年 - 1983) / 4))
    ElseIf (年 <= 2099) Then
        prv春分日 = Fix(20.8431 + (0.242194 * (年 - 1980)) - Fix((年 - 1980) / 4))
    ElseIf (年 <= 2150) Then
        prv春分日 = Fix(21.851 + (0.242194 * (年 - 1980)) - Fix((年 - 1980) / 4))
    Else
        prv春分日 = 99        '2151年以降は略算式が無いので不明
    End If
End Function

'========================================================================
Private Function prv秋分日(ByVal 年 As Integer) As Integer
    If (年 <= 1947) Then
        prv秋分日 = 99        '祝日法施行前
    ElseIf (年 <= 1979) Then
        '(年 - 1983)がマイナスになるので『Fix関数』にする
        prv秋分日 = Fix(23.2588 + (0.242194 * (年 - 1980)) - Fix((年 - 1983) / 4))
    ElseIf (年 <= 2099) Then
        prv秋分日 = Fix(23.2488 + (0.242194 * (年 - 1980)) - Fix((年 - 1980) / 4))
    ElseIf (年 <= 2150) Then
        prv秋分日 = Fix(24.2488 + (0.242194 * (年 - 1980)) - Fix((年 - 1980) / 4))
    Else
        prv秋分日 = 99        '2151年以降は略算式が無いので不明
    End If
End Function

'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
'_/  CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/





※ 2002/3/28追記(『祝日について』の春分/秋分日の補足説明参照)
        VBおよびVBAで『Int関数』を使う場合は、prv春分日/prv秋分日は
        下記のようにできます。

Private Function prv春分日(ByVal 年 As Integer) As Integer
    If (年 <= 1947) Then
        prv春分日 = 99        '祝日法施行前
    ElseIf (年 <= 1979) Then
        prv春分日 = Int(20.8357 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    ElseIf (年 <= 2099) Then
        prv春分日 = Int(20.8431 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    ElseIf (年 <= 2150) Then
        prv春分日 = Int(21.851 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    Else
        prv春分日 = 99        '2151年以降は略算式が無いので不明
    End If
End Function

'========================================================================
Private Function prv秋分日(ByVal 年 As Integer) As Integer
    If (年 <= 1947) Then
        prv秋分日 = 99        '祝日法施行前
    ElseIf (年 <= 1979) Then
        prv秋分日 = Int(23.2588 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    ElseIf (年 <= 2099) Then
        prv秋分日 = Int(23.2488 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    ElseIf (年 <= 2150) Then
        prv秋分日 = Int(24.2488 + (0.242194 * (年 - 1980)) - Int((年 - 1980) / 4))
    Else
        prv秋分日 = 99        '2151年以降は略算式が無いので不明
    End If
End Function


[ この場所へのリンク ]


Delphi 用祝日判定コード 】    [ 検証用データ ( 祝日一覧 ) は JavaScript 版による ツール で取得できます ]  [ 不具合報告 メール送信 ]
  2002/11/22 追記
  2005/5/20 [昭和の日] 改正の修正
  2014/5/29 [山の日] 改正の修正
  2018/2/15 [天皇誕生日の変更] 改正の修正
  2018/6/21 [体育の日⇒スポーツの日 改名] & [五輪特措法による祝日移動] 改正の修正
  2018/12/8 [即位の日 および 4/30 & 5/2の国民の休日] [即位礼正殿の儀] 改正の修正

    上記のVBAコードのロジックを、そのまま[Delphi]用に書き直したものです。
    土日なども一緒に判定するなど条件を付加する場合は、こちらの解説を参考にして下さい。
    『祝日について

    「昭和の日」に伴う「振替休日(5月6日)」改正への 修正方針 もお読みください。
    「即位の日(2019/5/1)」に伴う「祝日に挟まれた平日(4/30 & 5/2)の休日化」への修正方針もお読みください。


    ----------- Delphi における 曜日値について -----------
        曜日値を取得する関数が2つ ( DayOfTheWeek , DayOfWeek ) あります。
        DayOfTheWeek の曜日の値は [ 月(1), 火(2), 水(3), 木(4), 金(5), 土(6), 日(7) ] です。
        システム定数の [ DayMonday(1), DayTuesday(2), … DaySaturday(6), DaySunday(7) ] が利用できます。

        DayOfWeek の曜日の値は [ 日(1), 月(2), 火(3), 水(4), 木(5), 金(6), 土(7) ] です。
        DayOfWeek にシステム定数は用意されていません。


----------------------------------------------------------------------------------------
 


var
  function ktHolidayName(MyDate: TDateTime): AnsiString;
  function prvHolidayChk(MyDate: TDateTime): AnsiString;
  function prvDayOfSpringEquinox(MyYear: Integer): Integer;
  function prvDayOfAutumnEquinox(MyYear: Integer): Integer;

implementation
{
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/  --- Delphi 移植版 ( Update: 2018/12/8 ) ---
_/
_/  CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
_/  ( AddinBox  http://addinbox.sakura.ne.jp/index.htm )
_/  (  旧サイト  http://www.h3.dion.ne.jp/~sakatsu/index.htm )
_/
_/  この祝日判定コードは[Excel:kt関数アドイン]で使用している
_/  VBAマクロを[Delphi]に移植したものです。
_/
_/  この関数では以下の祝日変更までサポートしています。
_/    (a) 2019年施行の「天皇誕生日の変更」 12/23⇒2/23 (補:2019年には[天皇誕生日]はありません)
_/    (b) 2019年の徳仁親王の即位日(5/1) および
_/       祝日に挟まれて「国民の休日」となる 4/30(平成天皇の退位日) & 5/2 の2休日
_/    (c) 2019年の「即位の礼 正殿の儀 (10/22) 」
_/    (d) 2020年施行の「体育の日の改名」⇒スポーツの日
_/    (e) 五輪特措法による2020年の「祝日移動」
_/       海の日:7/20(3rd Mon)⇒7/23, スポーツの日:10/12(2nd Mon)⇒7/24, 山の日:8/11⇒8/10
_/
_/ (1) このコードを引用するに当たっては、必ずこのコメントも
_/      一緒に引用する事とします。
_/ (2) 他サイト上で本マクロを直接引用する事は、ご遠慮願います。
_/      [ http://addinbox.sakura.ne.jp/holiday_logic.htm ]
_/      へのリンクによる紹介で対応して下さい。
_/ (3) [ktHolidayName]という関数名そのものは、各自の環境に
_/      おける命名規則に沿って変更しても構いません。
_/
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

}

function ktHolidayName(MyDate: TDateTime) : AnsiString;
var
  dtmDate: TDateTime;
  strHolidayName: AnsiString;
begin
  dtmDate := DateOf(MyDate);      // 時刻の削除
  strHolidayName := prvHolidayChk(dtmDate);

  // ----- 振替休日の判定 (振替休日施行日:1973/4/12) -----
  // [ 対象日≠祝日/休日 & 対象日=月曜日 ]のみ、前日(=日曜日)を祝日判定する。
  // 前日(=日曜日)が祝日の場合は”振替休日”となる。
  // 尚、5月6日の扱いを
  //     「火曜 or 水曜(みどりの日(5/4) or 憲法記念日(5/3)の振替休日)」⇒5月ブロック内で判定済
  //     「月曜(こどもの日(5/5)の振替休日」⇒ここの判定処理で判定
  '//とする事により、ここでの判定対象は『対象日が月曜日』のみ となります。

  If (strHolidayName = '') then
      If (DayOfTheWeek(dtmDate) = DayMonday) then
          If (dtmDate >= EncodeDate(1973,4,12)) then
            begin
              strHolidayName := prvHolidayChk(IncDay(dtmDate, -1));
              If (strHolidayName <> '') then
                Result := '振替休日'
              else
                Result := '';
            end
          else
            Result := ''
      else
        Result := ''
  else
    Result := strHolidayName;
end;

//============[祝日判定 本体]============================
function prvHolidayChk(MyDate: TDateTime): AnsiString;
var
  MyYear, MyMonth, MyDay, MyAutumnEquinox: Integer;

// [MyDate]からは時刻が取り除いてあるので
// 「昭和天皇の大喪の礼」等の日付との比較はOK

begin
  MyYear := YearOf(MyDate);
  MyMonth := MonthOf(MyDate);  // 1〜12
  MyDay := DayOf(MyDate);

  Result := '';
  If (MyDate < EncodeDate(1948, 7, 20)) then
    exit;    //祝日法施行前

  Case MyMonth Of
  // 1月 //
    1: If (MyDay = 1) then
         Result := '元日'
       else
         If (MyYear >= 2000) then
           If ((((MyDay - 1) div 7) + 1) = 2) and
              (DayOfTheWeek(MyDate) = DayMonday) then    // 2nd Monday
             Result := '成人の日'
           else
         else
           If (MyDay = 15) Then
             Result := '成人の日'
           else;

  // 2月 //
    2: If (MyDay = 11) then
         If (MyYear >= 1967) then
           Result := '建国記念の日'
         else
       else If (MyDay = 23) then
         If (MyYear >= 2020) then
           Result := '天皇誕生日'
         else
       else If (MyDate = EncodeDate(1989,2,24)) then
         Result := '昭和天皇の大喪の礼'
       else;

  // 3月 //
    3: If (MyDay = prvDayOfSpringEquinox(MyYear)) then    // 1948〜2150以外は[99]
         Result := '春分の日'                              // が返るので、必ず≠になる
       else;

  // 4月 //
    4: If (MyDay = 29) then
         Case MyYear of
           2007..9999:
              Result := '昭和の日';
           1989..2006:
              Result := 'みどりの日';
           else
              Result := '天皇誕生日';  // 昭和天皇
         end
       else If (MyDate = EncodeDate(2019,4,30)) then
         Result := '国民の休日'    // 平成天皇の退位日,祝日に挟まれた国民の休日です
       else If (MyDate = EncodeDate(1959,4,10)) then
         Result := '皇太子明仁親王の結婚の儀'
       else;

  // 5月 //
    5: Case MyDay of
      // [火〜土]判定があるので、ここでは DayOfWeek [日(1),月(2),火(3),水(4)...土(7)] を使う
      // 定数:DayMonday(1),DayTuesday(2)等は値が異なるので使わない(DayOfTheWeek 用)
        3: Result := '憲法記念日';
        4: Case MyYear of
              2007..9999:
                  Result := 'みどりの日';
              1986..2006:
                  If (DayOfWeek(MyDate) > 2) then    // 火曜(3) 以降(火〜土)
                      // 5/4が日曜日は『只の日曜』、月曜日は『憲法記念日の振替休日』(〜2006年)
                      Result := '国民の休日'
                  else
              else
          end;
        5: Result := 'こどもの日';
        6: If (MyYear >= 2007) then
              Case DayOfWeek(MyDate) of          // [5/3,5/4が日曜]ケースのみ、ここで判定
                  3, 4: Result := '振替休日';    // 火曜(3) or 水曜(4)
                  else
              end
           else
        else
          If (MyYear = 2019) then
              If (MyDate = EncodeDate(2019,5,1)) then    // 徳仁親王の即位日
                  Result := '即位の日'
              else If (MyDate = EncodeDate(2019,5,2)) then
                  Result := '国民の休日'    // 祝日に挟まれた国民の休日です
              else
          else
      end;

  // 6月 //
    6: If (MyDate = EncodeDate(1993,6,9)) then
         Result := '皇太子徳仁親王の結婚の儀'
       else;

  // 7月 //
    7: If (MyYear >= 2021) then
         If ((((MyDay - 1) div 7) + 1) = 3) and
            (DayOfTheWeek(MyDate) = DayMonday) then    // 3rd Monday
           Result := '海の日'
         else
       else If (MyYear = 2020) then
         // 2020年はオリンピック特措法により
         //「海の日」が 7/23 ,「スポーツの日」が 7/24 に移動
         Case MyDay of
            23: Result := '海の日';
            24: Result := 'スポーツの日';
         end
       else If (MyYear >= 2003) then
         If ((((MyDay - 1) div 7) + 1) = 3) and
            (DayOfTheWeek(MyDate) = DayMonday) then    // 3rd Monday
           Result := '海の日'
         else
       else If (MyYear >= 1996) then
         If (MyDay = 20) then
           Result := '海の日'
         else
       else;

  // 8月 //
    8: If (MyYear >= 2021) then
         If (MyDay = 11) Then
           Result := '山の日'
         else
       else If (MyYear = 2020) then
         If (MyDay = 10) Then
           // 2020年はオリンピック特措法により「山の日」が 8/10 に移動
           Result := '山の日'
         else
       else If (MyYear >= 2016) then
         If (MyDay = 11) Then
           Result := '山の日'
         else
       else;

  // 9月(第3月曜日(15〜21)と秋分日(22〜24)が重なる事はない) //
    9:
      begin
        MyAutumnEquinox := prvDayOfAutumnEquinox(MyYear);
        If (MyDay = MyAutumnEquinox) then    // 1948〜2150以外は[99]
          Result := '秋分の日'              // が返るので、必ず≠になる
        else
          If (MyYear >= 2003) Then
            If ((((MyDay - 1) div 7) + 1) = 3) and
               (DayOfTheWeek(MyDate) = DayMonday) then    // 3rd Monday
              Result := '敬老の日'
            else
              If (DayOfTheWeek(MyDate) = DayTuesday) and
                (MyDay = (MyAutumnEquinox - 1)) then
                Result := '国民の休日'    // 火曜日&[秋分日の前日]
              else
          else
            If (MyYear >= 1966) and (MyDay = 15) then
              Result := '敬老の日'
            else;
      end;

  // 10月 //
    10: If (MyYear >= 2021) then
          If ((((MyDay - 1) div 7) + 1) = 2) and
             (DayOfTheWeek(MyDate) = DayMonday) then    // 2nd Monday
            Result := 'スポーツの日'    // 2020年より改名
          else
        else If (MyYear = 2020) then
          // 2020年はオリンピック特措法により「スポーツの日」が 7/24 に移動
          begin
          end
        else If (MyYear >= 2000) then
          If ((((MyDay - 1) div 7) + 1) = 2) and
             (DayOfTheWeek(MyDate) = DayMonday) then    // 2nd Monday
            Result := '体育の日'
          else If (MyDate = EncodeDate(2019,10,22)) then    // 即位礼正殿の儀,徳仁親王)
            Result := '即位礼正殿の儀'
          else
        else If (MyYear >= 1966) then
          If (MyDay = 10) Then
            Result := '体育の日'
          else
        else;

  // 11月 //
    11: If (MyDay = 3) then
          Result := '文化の日'
        else If (MyDay = 23) then
          Result := '勤労感謝の日'
        else If (MyDate = EncodeDate(1990,11,12)) then
          Result := '即位礼正殿の儀'    // 平成天皇
        else;

  // 12月 //
    12: If ((MyYear >= 1989) and (MyYear <= 2018)) and (MyDay = 23) Then
          Result := '天皇誕生日 // 平成天皇
        else;
  end
end;

//==================================================================
//  春分/秋分日の略算式は
//    『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』
//  で紹介されている式です。

function prvDayOfSpringEquinox(MyYear: Integer): Integer;
begin
  Case MyYear of
    1948..1979:
      Result := Trunc(20.8357 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1983) / 4));
    1980..2099:
      Result := Trunc(20.8431 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1980) / 4));
    2100..2150:
      Result := Trunc(21.851 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1980) / 4));
    else
      Result := 99;    // 祝日法施行前および
                      // 2151年以降は略算式が無いので不明
  end
end;

//=================================================================
function prvDayOfAutumnEquinox(MyYear: Integer): Integer;
begin
  Case MyYear of
    1948..1979:
      Result := Trunc(23.2588 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1983) / 4));
    1980..2099:
      Result := Trunc(23.2488 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1980) / 4));
    2100..2150:
      Result := Trunc(24.2488 +
                  (0.242194 * (MyYear - 1980)) - Int((MyYear - 1980) / 4));
    else
      Result := 99;    // 祝日法施行前および
                      // 2151年以降は略算式が無いので不明
  end
end;

// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
// _/  CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/




[ この場所へのリンク ]


JavaScript 用祝日判定コード 】    [ 検証用データ ( 祝日一覧 ) は JavaScript 版による ツール で取得できます ]  [ 不具合報告 メール送信 ]
  2003/5/9 追記 , 2005/5/20 [昭和の日] 改正の修正
  2008/10/29 var 指定が無かったので修正
  2011/ 3/20 [FireFox TraceMonkey バグ]対応で修正
  2014/ 5/29 [山の日] 改正の修正
  2015/ 7/11 [1970/1/1 以降のみ可]の制限を解除
  2018/ 2/15 [天皇誕生日の変更] 改正の修正
  2018/ 6/21 [体育の日⇒スポーツの日 改名] & [五輪特措法による祝日移動] 改正の修正
  2018/12/ 8 [即位の日 および 4/30 & 5/2の国民の休日] [即位礼正殿の儀] 改正の修正
  2018/12/11 引数の制限事項を追記( ソースコード先頭のコメントを参照)

    上記のVBAコードのロジックを、そのまま[Java Script ]用に書き直したものです。
    土日なども一緒に判定するなど条件を付加する場合は、こちらの解説を参考にして下さい。
    この[JavaScript]コードは『祝日について』ページの祝日一覧表示ボタンで使っています。

    JavaScript ファイル(下記) : HolidayChk.js 

    「昭和の日」に伴う「振替休日(5月6日)」改正への 修正方針 もお読みください。
    「即位の日(2019/5/1)」に伴う「祝日に挟まれた平日(4/30 & 5/2)の休日化」への修正方針もお読みください。


    ----------- JavaScript における 曜日値について -----------
        曜日の値は [ 日(0), 月(1), 火(2), 水(3), 木(4), 金(5), 土(6) ] です。
        システム定数は用意されていません。

----------------------------------------------------------------------------------------

 


<!--
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/
//_/  --- JavaScript 移植版 ( Update: 2018/12/11 ) ---
//_/
//_/ CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
//_/ ( AddinBox  http://addinbox.sakura.ne.jp/index.htm )
//_/ (   旧サイト  http://www.h3.dion.ne.jp/~sakatsu/index.htm )
//_/
//_/ この祝日判定コードは『Excel:kt関数アドイン』で使用している
//_/ VBAマクロを[JavaScript]に移植したものです。
//_/
//_/ この関数では以下の祝日変更までサポートしています。
//_/    (a) 2019年施行の「天皇誕生日の変更」 12/23⇒2/23 (補:2019年には[天皇誕生日]はありません)
//_/    (b) 2019年の徳仁親王の即位日(5/1) および
//_/       祝日に挟まれて「国民の休日」となる 4/30(平成天皇の退位日) & 5/2 の2休日
//_/    (c) 2019年の「即位の礼 正殿の儀 (10/22) 」
//_/    (d) 2020年施行の「体育の日の改名」⇒スポーツの日
//_/    (e) 五輪特措法による2020年の「祝日移動」
//_/       海の日:7/20(3rd Mon)⇒7/23, スポーツの日:10/12(2nd Mon)⇒7/24, 山の日:8/11⇒8/10
//_/
//_/ (*1)このコードを引用するに当たっては、必ずこのコメントも
//_/     一緒に引用する事とします。
//_/ (*2)他サイト上で本マクロを直接引用する事は、ご遠慮願います。
//_/     【 http://addinbox.sakura.ne.jp/holiday_logic.htm 】
//_/     へのリンクによる紹介で対応して下さい。
//_/ (*3)[ktHolidayName]という関数名そのものは、各自の環境に
//_/     おける命名規則に沿って変更しても構いません。
//_/
//_/  --- 引数 制限事項 ---
//_/  ktHolidayName にはスラッシュ区切の日付フォーマット(YYYY/M/D)で渡す。
//_/  ハイフン区切の日付フォーマット(YYYY-MM-DD)は不可。
//_/  ( 理由 )
//_/  YYYY-MM-DDは[new Date]の際に UTC に変換される(実行地域での時差が反映される)為、
//_/  ktHolidayName内の日付定数(時刻=0:0:0)と一致しない。
//_/  日本では[+9:00]の時刻が付く。アメリカ西海岸では[-8:00]で前日の日付になる。
//_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//
// 2008/10/29 変数のvar指定が無く、広域変数扱いになっていたのを修正しました。
//
// 2014/5/29 「山の日」の祝日法改正
//
// 2015/7/11  JavaScript1.3 以降では[1970/1/1]以前も扱えるため、日付範囲の制限を解除
//
// 2018/2/15 「天皇誕生日の変更」の祝日法改正
//
// 2018/6/21 [体育の日⇒スポーツの日 改名] & [五輪特措法による祝日移動] 改正の修正
//
// 2018/12/8 2019年の即位関連休日の修正
//
// 2018/12/11 先頭コメントに引数制限事項を追記


var MONDAY = 1;    // [ 日(0), 月(1), … 土(6) ]
var TUESDAY = 2;
var WEDNESDAY = 3;

var cstImplementTheLawOfHoliday = new Date("1948/7/20");   // 祝日法施行
var cstAkihitoKekkon = new Date("1959/4/10");              // 明仁親王の結婚の儀
var cstShowaTaiso = new Date("1989/2/24");                 // 昭和天皇大喪の礼
var cstNaruhitoKekkon = new Date("1993/6/9");              // 徳仁親王の結婚の儀
var cstSokuireiSeiden = new Date("1990/11/12");            // 即位礼正殿の儀(平成天皇)
var cstImplementTransferHoliday = new Date("1973/4/12");   // 振替休日施行

var cstTaii_Heisei = new Date("2019/4/30");               // 祝日ではなく「国民の休日」です
var cstSokui_Naruhito = new Date ("2019/5/1");            // 即位の日(徳仁親王)
var cst2019GW_May2nd = new Date("2019/5/2");              // 祝日ではなく「国民の休日」です
var cstSokuireiSeiden_Naruhito = new Date("2019/10/22");  // 即位礼正殿の儀(徳仁親王)

// [prmDate]には "yyyy/m/d"形式の日付文字列を渡す
function ktHolidayName(prmDate)
{
  var YesterDay;
  var HolidayName_ret;
  var MyDate = new Date(prmDate);
  var HolidayName = prvHolidayChk(MyDate);

  // ----- 振替休日の判定 (振替休日施行日:1973/4/12) -----
  // [ 対象日≠祝日/休日 & 対象日=月曜日 ]のみ、前日(=日曜日)を祝日判定する。
  // 前日(=日曜日)が祝日の場合は”振替休日”となる。
  // 尚、5月6日の扱いを
  //     「火曜 or 水曜(みどりの日(5/4) or 憲法記念日(5/3)の振替休日)」⇒5月ブロック内で判定済
  //     「月曜(こどもの日(5/5)の振替休日」⇒ここの判定処理で判定
  // とする事により、ここでの判定対象は『対象日が月曜日』のみ となります。

  if (HolidayName == "") {
      if (MyDate.getDay() == MONDAY) {
          if (MyDate.getTime() >= cstImplementTransferHoliday.getTime()) {
              YesterDay = new Date(MyDate.getFullYear(),
                                    MyDate.getMonth(),(MyDate.getDate()-1));
              HolidayName = prvHolidayChk(YesterDay);
              if (HolidayName != "") {
                  HolidayName_ret = "振替休日";
              } else {
                  HolidayName_ret = "";
              }
          } else {
              HolidayName_ret = "";
          }
      } else {
          HolidayName_ret = "";
      }
  } else {
      HolidayName_ret = HolidayName;
  }

  return HolidayName_ret;
}

//===============================================================

function prvHolidayChk(MyDate)
{
  var MyYear = MyDate.getFullYear();
  var MyMonth = MyDate.getMonth() + 1;    // MyMonth:1〜12
  var MyDay = MyDate.getDate();
  var NumberOfWeek;
  var MyAutumnEquinox;

  var Result = "";

  if (MyDate.getTime() < cstImplementTheLawOfHoliday.getTime()) {
    return ""; // 祝日法施行(1948/7/20)以前
  } else;

  switch (MyMonth) {
// 1月 //
  case 1:
      if (MyDay == 1) {
          Result = "元日";
      } else {
          if (MyYear >= 2000) {
              NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;
              if ((NumberOfWeek == 2) && (MyDate.getDay() == MONDAY)) {    // 2nd Monday
                  Result = "成人の日";
              } else;
          } else {
              if (MyDay == 15) {
                  Result = "成人の日";
              } else;
          }
      }
      break;

// 2月 //
  case 2:
      if (MyDay == 11) {
          if (MyYear >= 1967) {
              Result = "建国記念の日";
          } else;
      } else {
          if (MyDay == 23) {
              if (MyYear >= 2020) {
                  Result = "天皇誕生日";
              } else;
          } else {
              if (MyDate.getTime() == cstShowaTaiso.getTime()) {
                  Result = "昭和天皇の大喪の礼";
              } else;
          }
      }
      break;

// 3月 //
  case 3:
      if (MyDay == prvDayOfSpringEquinox(MyYear)) {  // 1948〜2150以外は[99]
          Result = "春分の日";                      // が返るので、必ず≠になる
      } else;
      break;

// 4月 //
  case 4:
      if (MyDay == 29) {
          if (MyYear >= 2007) {
              Result = "昭和の日";
          } else {
              if (MyYear >= 1989) {
                  Result = "みどりの日";
              } else {
                Result = "天皇誕生日";
              }
          }
      } else {
          if (MyDate.getTime() == cstTaii_Heisei.getTime()) {  // (2019/4/30)
              Result = "国民の休日";    // 祝日に挟まれた国民の休日(平成天皇の退位日)
          } else {
              if (MyDate.getTime() == cstAkihitoKekkon.getTime()) {    // (1959/4/10)
                  Result = "皇太子明仁親王の結婚の儀";
              } else;
          }
      }
      break;

// 5月 //
  case 5:
      switch ( MyDay ) {
        case 3:  // 5月3日
          Result = "憲法記念日";
          break;
        case 4:  // 5月4日
          if (MyYear >= 2007) {
              Result = "みどりの日";
          } else {
              if (MyYear >= 1986) {
                  if (MyDate.getDay() > MONDAY) {  // 火曜 以降(火〜土)
                  // 5/4が日曜日は『只の日曜』、月曜日は『憲法記念日の振替休日』(〜2006年)
                      Result = "国民の休日";
                  } else;
              } else;
          }
          break;
        case 5:  // 5月5日
          Result = "こどもの日";
          break;
        case 6:  // 5月6日
          if (MyYear >= 2007) {
              if ((MyDate.getDay() == TUESDAY) || (MyDate.getDay() == WEDNESDAY)) {
                  Result = "振替休日";    // [5/3,5/4が日曜]ケースのみ、ここで判定
              } else;
          } else;
          break;
        default:  // その他
          if (MyYear == 2019) {
              if (MyDate.getTime() == cstSokui_Naruhito.getTime()) {  // (2019/5/1)
                  Result = "即位の日";      // 徳仁親王の即位の日
              } else {
                  if (MyDate.getTime() == cst2019GW_May2nd.getTime()) {  // (2019/5/2)
                      Result = "国民の休日";    // 祝日に挟まれた国民の休日
                  } else;
              }
          } else;
      }
      break;

// 6月 //
  case 6:
      if (MyDate.getTime() == cstNaruhitoKekkon.getTime()) {
          Result = "皇太子徳仁親王の結婚の儀";
      } else;
      break;

// 7月 //
  case 7:
      NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;
      if (MyYear >= 2021) {
          if ((NumberOfWeek == 3) && (MyDate.getDay() == MONDAY)) {  // 3rd Monday
              Result = "海の日";
          } else;
      } else {
          if (MyYear == 2020) {
              // 2020年はオリンピック特措法により
              //「海の日」が 7/23 / 「スポーツの日」が 7/24 に移動
              if (MyDay == 23) {
                  Result = "海の日";
              } else {
                  if (MyDay == 24) {
                      Result = "スポーツの日";
                  } else;
              }
          } else {
              if (MyYear >= 2003) {
                  if ((NumberOfWeek == 3) && (MyDate.getDay() == MONDAY)) {  // 3rd Monday
                      Result = "海の日";
                  } else;
              } else {
                  if (MyYear >= 1996) {
                      if (MyDay == 20) {
                          Result = "海の日";
                      } else;
                  } else;
              }
          }
      }
      break;

// 8月 //
  case 8:
      if (MyYear >= 2021) {
          if (MyDay == 11) {
              Result = "山の日";
          } else;
      } else {
          if (MyYear == 2020) {
              // 2020年はオリンピック特措法により「山の日」が 8/10 に移動
              if (MyDay == 10) {
                  Result = "山の日";
              } else;
          } else {
              if (MyYear >= 2016) {
                  if (MyDay == 11) {
                      Result = "山の日";
                  } else;
              } else;
          }
      }
      break;

// 9月 //
  case 9:
      //第3月曜日(15〜21)と秋分日(22〜24)が重なる事はない
      MyAutumnEquinox = prvDayOfAutumnEquinox(MyYear);
      if (MyDay == MyAutumnEquinox) {    // 1948〜2150以外は[99]
          Result = "秋分の日";          // が返るので、必ず≠になる
      } else {
          if (MyYear >= 2003) {
              NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;
              if ((NumberOfWeek == 3) && (MyDate.getDay() == MONDAY)) {    // 3rd Monday
                  Result = "敬老の日";
              } else {
                  if (MyDate.getDay() == TUESDAY) {
                      if (MyDay == (MyAutumnEquinox - 1)) {
                          Result = "国民の休日";    // 火曜日&[秋分日の前日]
                      } else;
                  } else;
              }
          } else {
              if (MyYear >= 1966) {
                  if (MyDay == 15) {
                      Result = "敬老の日";
                  } else;
              } else;
          }
      }
      break;

// 10月 //
  case 10:
      NumberOfWeek = Math.floor(( MyDay - 1) / 7) + 1;
      if (MyYear >= 2021) {
          if ((NumberOfWeek == 2) && (MyDate.getDay() == MONDAY)) {  // 2nd Monday
              Result = "スポーツの日";  // 2020年より改名
          } else;
      } else {
          if (MyYear == 2020) {
              // 2020年はオリンピック特措法により「スポーツの日」が 7/24 に移動
          } else {
              if (MyYear >= 2000) {
                  if ((NumberOfWeek == 2) && (MyDate.getDay() == MONDAY)) {    // 2nd Monday
                      Result = "体育の日";
                  } else {
                      if (MyDate.getTime() == cstSokuireiSeiden_Naruhito.getTime()) {  // (2019/10/22)
                          Result = "即位礼正殿の儀";      // 徳仁親王
                      } else;
                  }
              } else {
                  if (MyYear >= 1966) {
                      if (MyDay == 10) {
                          Result = "体育の日";
                      } else;
                  } else;
              }
          }
      }
      break;

// 11月 //
  case 11:
      if (MyDay == 3) {
          Result = "文化の日";
      } else {
          if (MyDay == 23) {
              Result = "勤労感謝の日";
          } else {
              if (MyDate.getTime() == cstSokuireiSeiden.getTime()) {
                  Result = "即位礼正殿の儀";    // 平成天応
              } else;
          }
      }
      break;

// 12月 //
  case 12:
      if (MyDay == 23) {
          if ((MyYear >= 1989) && (MyYear <= 2018)) {
              Result = "天皇誕生日";  // 平成天皇
          } else;
      } else;
      break;
  }

  return Result;
}

//===================================================================
// 春分/秋分日の略算式は
// 『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』
// で紹介されている式です。

function prvDayOfSpringEquinox(MyYear)
{
  var SpringEquinox_ret;

  if (MyYear <= 1947) {
      SpringEquinox_ret = 99;    //祝日法施行前
  } else {
      if (MyYear <= 1979) {
          // Math.floor 関数は[VBAのInt関数]に相当
          SpringEquinox_ret = Math.floor(20.8357 +
            (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
      } else {
          if (MyYear <= 2099) {
              SpringEquinox_ret = Math.floor(20.8431 +
                (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
          } else {
              if (MyYear <= 2150) {
                  SpringEquinox_ret = Math.floor(21.851 +
                    (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
              } else {
                  SpringEquinox_ret = 99;    //2151年以降は略算式が無いので不明
              }
          }
      }
  }
  return SpringEquinox_ret;
}

//=====================================================================
function prvDayOfAutumnEquinox(MyYear)
{
  var AutumnEquinox_ret;

  if (MyYear <= 1947) {
      AutumnEquinox_ret = 99; //祝日法施行前
  } else {
      if (MyYear <= 1979) {
          // Math.floor 関数は[VBAのInt関数]に相当
          AutumnEquinox_ret = Math.floor(23.2588 +
            (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
      } else {
          if (MyYear <= 2099) {
              AutumnEquinox_ret = Math.floor(23.2488 +
                (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
          } else {
              if (MyYear <= 2150) {
                  AutumnEquinox_ret = Math.floor(24.2488 +
                    (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));
              } else {
                  AutumnEquinox_ret = 99;    //2151年以降は略算式が無いので不明
              }
          }
      }
  }
  return AutumnEquinox_ret;
}

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/ CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

-->


[春分日/秋分日]算出式の『1979年以前』のコードが、VBAやC言語のコードと異なる
    理由はこちらの解説をご覧下さい。
    JavaScriptの[ Math.floor 関数]では【 Math.floor( -8.4 ) → -9 】です。

----- [ Java Script ]用の実行サンプルHTML -------
    上記のコードを下記の部分にコピーして使って下さい。
<HTML>
<HEAD>
<TITLE></TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--
    【この場所に 上記のJavaScriptコードを貼り付けます】

var WeekName = new Array(7);
WeekName[0] = "日";
WeekName[1] = "月";
WeekName[2] = "火";
WeekName[3] = "水";
WeekName[4] = "木";
WeekName[5] = "金";
WeekName[6] = "土";

function getWeekName(Week) {  // 曜日の日本語名変換
  return WeekName[Week];
}

function sample1() {
  document.Form1.TextBox2.value =
              ktHolidayName(document.Form1.TextBox1.value);
}

function sample2() {
  var OneDay = 24 * 60 * 60 * 1000;    // 1日をミリ秒で表現
  var FirstDate = new Date("2017/1/1");
  var LastDate = new Date("2030/11/31");
  var wkDate = FirstDate;
  var strDate;
  var HName;

  DW1=window.open("","Holiday_Name_List","menubar=yes,location=no,scrollbars=yes,status=yes");
  DW1.document.open();
  DW1.document.write('<HTML>\n<HEAD>\n<TITLE>Holiday_Name_List</TITLE>\n</HEAD>\n<BODY>\n<P>\n');

  while (wkDate.getTime() < LastDate.getTime()) {
    strDate = wkDate.getFullYear() + "/" +
                    (wkDate.getMonth() + 1) + "/" + wkDate.getDate();
    HName = ktHolidayName(strDate);
    if (HName != "") {
        DW1.document.write(strDate + "(" +
              getWeekName(wkDate.getDay()) + ")" + HName + "<BR>\n");
    }
    wkDate.setTime(wkDate.getTime() + OneDay);
  }

  DW1.document.write('</P>\n</BODY>\n</HTML>');
  DW1.document.close();

}
//-->
</SCRIPT>
</HEAD>
<BODY>
日付を yyyy/mm/dd 形式で入力して変換ボタンをクリック<BR>
<FORM name="Form1">
<INPUT size="20" type="text" name="TextBox1">
<INPUT type="button" name="Button1" value="⇒ 祝日の表示 ⇒" onclick="sample1();">
<INPUT size="20" type="text" name="TextBox2"><BR><BR>
下記のボタンで 2017/1/1〜2030/12/31 の期間の祝日一覧を表示します。<BR>
<INPUT type="button" name="Button2"
  value="2017年〜2030年の祝日一覧" onclick="sample2();">
</FORM>
</BODY>
</HTML>

---------------------------------------------------------------------
日付を yyyy/mm/dd 形式で入力して変換ボタンをクリック


下記のボタンで 2017/1/1〜2030/12/31 の期間の祝日一覧を表示します。
---------------------------------------------------------------------
 All About Japan[ JavaScript ]高橋 登史朗さん )で紹介されている、
 JavaScriptによる日付入力ポップアップフォーム に、
 上記ロジックによる「祝日表示 他」の修正を加えたものを こちら で、ご覧頂けます。(2004/7/9 追記)


[ この場所へのリンク ]


OpenOffice.org Basic 用祝日判定コード 】    [ 検証用データ ( 祝日一覧 ) は JavaScript 版による ツール で取得できます ]  [ 不具合報告 メール送信 ]
    ( Apache OpenOffice , LibreOffice )
  2005/4/15 追記
  2005/5/20 [昭和の日]改正の修正
  2014/5/29 [山の日]改正の修正
  2018/2/15 [天皇誕生日の変更] 改正の修正
  2018/6/21 [体育の日⇒スポーツの日 改名] & [五輪特措法による祝日移動] 改正の修正
  2018/12/8 [即位の日 および 4/30 & 5/2の国民の休日] [即位礼正殿の儀] 改正の修正

    上記のVBAコードのロジックを、そのまま[OpenOffice.org Basic ]用に書き直したものです(英語版)。
    VBAとの違いによる変更点は下記になります。
        (1) 変数名等に日本語名が使えない
        (2) vbMonday等のVB定数に相当するものが無いので、Constant を用意
        (3) 定数定義において["]で囲んだ日付文字列で指定すると、極端に実行速度が落ちた為、
            [#]で囲んだ日付リテラルによる指定に変更
            #1959/4/10# という日付リテラル形式が OOoBasic では単なる割り算と解釈(=48.975)
            される為、シリアル値(21650)で定数定義するように変更
        (4) [Private]を指定しても無視されてマクロダイアログに現れる為、
            prv祝日/prv春分日/prv秋分日を独立させずに全てktHolidayNameにまとめる
        (5) (4)の変更に伴い、振替休日判定をルーチン内の最後に配置し、
            再帰呼出方式により実行する
    逆に、この OOoBasic 用コードは、そのまま何も修正する事無く VBA で動作します。

    土日なども一緒に判定するなど条件を付加する場合は、こちらの解説を参考にして下さい。
    『祝日について

    「昭和の日」に伴う「振替休日(5月6日)」改正への 修正方針 もお読みください。
    「即位の日(2019/5/1)」に伴う「祝日に挟まれた平日(4/30 & 5/2)の休日化」への修正方針もお読みください。


    ----------- Open Office.org Basic における 曜日値について -----------
        曜日の値は [ 日(1), 月(2), 火(3), 水(4), 木(5), 金(6), 土(7) ] です。
        システム定数は用意されていません。


----------------------------------------------------------------------------------------
 


'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
'_/
'_/  --- OpenOffice.org Basic 移植版 ( Update: 2018/12/8 ) ---
'_/    ( Apache OpenOffice , LibreOffice )
'_/
'_/  CopyRight(C) K.Tsunoda(AddinBox) 2005 All Rights Reserved.
'_/  ( AddinBox  http://addinbox.sakura.ne.jp/index.htm )
'_/  (    旧サイト  http://www.h3.dion.ne.jp/~sakatsu/index.htm )
'_/
'_/  この祝日判定コードは『Excel:kt関数アドイン』で使用している
'_/  VBAマクロを[OpenOffice.org Basic]に移植したものです。
'_/  このロジックは、レスポンスを第一義として、可能な限り少ない
'_/  【条件判定の実行】で結果を出せるように設計してあります。
'_/
'_/  この関数では以下の祝日変更までサポートしています。
'_/    (a) 2019年施行の「天皇誕生日の変更」 12/23⇒2/23 (補:2019年には[天皇誕生日]はありません)
'_/    (b) 2019年の徳仁親王の即位日(5/1) および
'_/       祝日に挟まれて「国民の休日」となる 4/30(平成天皇の退位日) & 5/2 の2休日
'_/    (c) 2019年の「即位の礼 正殿の儀 (10/22) 」
'_/    (d) 2020年施行の「体育の日の改名」⇒スポーツの日
'_/    (e) 五輪特措法による2020年の「祝日移動」
'_/       海の日:7/20(3rd Mon)⇒7/23, スポーツの日:10/12(2nd Mon)⇒7/24, 山の日:8/11⇒8/10
'_/
'_/  (*1)このマクロを引用するに当たっては、必ずこのコメントも
'_/      一緒に引用する事とします。
'_/  (*2)他サイト上で本マクロを直接引用する事は、ご遠慮願います。
'_/      【 http://addinbox.sakura.ne.jp/holiday_logic.htm 】
'_/      へのリンクによる紹介で対応して下さい。
'_/  (*3)[ktHolidayName]という関数名そのものは、各自の環境に
'_/      おける命名規則に沿って変更しても構いません。
'_/ 
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


Function ktHolidayName(ByVal ChkDate As Date) As String
Dim strHoliday As String
Dim intYear As Integer
Dim intMonth As Integer
Dim intDay As Integer
Dim intVernalEquinox As Integer
Dim intAutumnalEquinox As Integer
Dim strWeek As String

Const cstMonday As Integer = 2    ' [日(1), 月(2), … 土(7)]
Const cstTuesday As Integer = 3
Const cstWednesday As Integer = 4

'(注) 日付定数を日付文字列( "1959/4/10" 等 )で定義すると、極端に実行速度が落ちる。
'    また、[ #1959/4/10# 等 ]という日付リテラル形式が OOoBasic では単なる割り算と解釈(=48.975)される。
'    その為、日付定数はシリアル値(21650 等)で定義する。

Const cstImplementTheLawOfHoliday As Date = 17734  '祝日法施行(1948/7/20)
Const cstImplementHolidayInLieu As Date = 26766    '振替休日施行(1973/4/12)
Const cstShowaTaiso As Date = 32563                '昭和天皇の大喪の礼(1989/2/24)
Const cstAkihitoKekkon As Date = 21650             '明仁親王の結婚の儀(1959/4/10)
Const cstNaruhitoKekkon As Date = 34129            '徳仁親王の結婚の儀(1993/6/9)
Const cstSokuireiSeiden As Date = 33189            '即位礼正殿の儀(平成天皇 , 1990/11/12)

Const cstTaii_Heisei As Date = 43585               '祝日ではなく「国民の休日」です(2019/4/30)
Const cstSokui_Naruhito As Date = 43586            '即位の日(徳仁親王)(2019/5/1)
Const cst2019GW_May2nd As Date = 43587             '祝日ではなく「国民の休日」です(2019/5/2)
Const cstSokuireiSeiden_Naruhito As Date = 43760   '即位礼正殿の儀(徳仁親王)(2019/10/22)

    intYear = Year(ChkDate)
    intMonth = Month(ChkDate)
    intDay = Day(ChkDate)

    strHoliday = ""
    If (ChkDate < cstImplementTheLawOfHoliday) Then
        ktHolidayName = ""  ' 祝日法施行以前
        Exit Function
    End If

    Select Case intMonth
    '-- 1月 --
    Case 1
        If (intDay = 1) Then
            strHoliday = "元日"
        Else
            If (intYear >= 2000) Then
                strWeek = (((intDay - 1) \ 7) + 1) & Weekday(ChkDate)
                If (strWeek = "22") Then  '2nd Monday(2)
                    strHoliday = "成人の日"
                End If
            Else
                If (intDay = 15) Then
                    strHoliday = "成人の日"
                End If
            End If
        End If

    '-- 2月 --
    Case 2
        If (intDay = 11) Then
            If (intYear >= 1967) Then
                strHoliday = "建国記念の日"
            End If
        ElseIf (intDay = 23) Then
            If (intYear >= 2020) Then
                strHoliday = "天皇誕生日"
            End If
        ElseIf (ChkDate = cstShowaTaiso) Then    '(1989/2/24)
            strHoliday = "昭和天皇の大喪の礼"
        End If

    '-- 3月 --
    Case 3
        '春分/秋分日の略算式は『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』
        'で紹介されている式です。

        If (intYear <= 1947) Then
            intVernalEquinox = 99        '祝日法施行前
        ElseIf (intYear <= 1979) Then
            '(年 - 1983)がマイナスになるので『Fix関数』にする
            intVernalEquinox = Fix(20.8357 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1983) / 4))
        ElseIf (intYear <= 2099) Then
            intVernalEquinox = Fix(20.8431 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1980) / 4))
        ElseIf (intYear <= 2150) Then
            intVernalEquinox = Fix(21.851 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1980) / 4))
        Else
            intVernalEquinox = 99      ' 2151年以降は略算式が無いので不明
        End If

        If (intDay = intVernalEquinox) Then        ' 1948〜2150以外は[99]
            strHoliday = "春分の日"                ' が返るので、必ず≠になる
        End If

    '-- 4月 --
    Case 4
        If (intDay = 29) Then
            If (intYear >= 2007) Then
                strHoliday = "昭和の日"
            ElseIf  (intYear >= 1989) Then
                strHoliday = "みどりの日"
            Else
                strHoliday = "天皇誕生日' 昭和天皇
            End If
        ElseIf (ChkDate = cstTaii_Heisei) Then    ' 2019/4/30(平成天皇の退位日)
            strHoliday = "国民の休日"    '祝日に挟まれた国民の休日です
        ElseIf (ChkDate = cstAkihitoKekkon) Then    '(1959/4/10)
            strHoliday = "皇太子明仁親王の結婚の儀"
        End If

    '-- 5月 --
    Case 5
        If (intDay = 3) Then
            strHoliday = "憲法記念日"
        ElseIf (intDay = 4) Then
            If (intYear >= 2007) Then
                strHoliday = "みどりの日"
            ElseIf (intYear >= 1986) Then
                ' 5/4が日曜日は『只の日曜』、月曜日は『憲法記念日の振替休日』(〜2006年)
                If (Weekday(ChkDate) > cstMonday) Then  ' 火曜 以降(火〜土)
                    strHoliday = "国民の休日"
                End If
            End If
        ElseIf (intDay = 5) Then
            strHoliday = "こどもの日"
        ElseIf (intDay = 6) Then
            If (intYear >= 2007) Then
                Select Case Weekday(ChkDate)
                    Case cstTuesday, cstWednesday
                        strHoliday = "振替休日"    ' [5/3,5/4が日曜]ケースのみ、ここで判定
                End Select
            End If
        Else
            If (intYear = 2019) Then
                If (ChkDate = cstSokui_Naruhito) Then    ' 2019/5/1
                    strHoliday = "即位の日"    ' 徳仁親王
                ElseIf (ChkDate = cst2019GW_May2nd) Then    ' 2019/5/2
                    strHoliday = "国民の休日"    '祝日に挟まれた国民の休日です
                End If
            End If
        End If

    '-- 6月 --
    Case 6
        If (ChkDate = cstNaruhitoKekkon) Then    '(1993/6/9)
            strHoliday = "皇太子徳仁親王の結婚の儀"
        End If

    '-- 7月 --
    Case 7
        strWeek = (((intDay - 1) \ 7) + 1) & Weekday(ChkDate)
        If (intYear >= 2021) Then
            If (strWeek = "32") Then  '3rd Monday(2)
                strHoliday = "海の日"
            End If
        ElseIf (intYear = 2020) Then
            '2020年はオリンピック特措法により
            '「海の日」が 7/23 / 「スポーツの日」が 7/24 に移動
            If (intDay = 23) Then
                strHoliday = "海の日"
            ElseIf (intDay = 24) Then
                strHoliday = "スポーツの日"
            End If
        ElseIf (intYear >= 2003) Then
            If (strWeek = "32") Then  '3rd Monday(2)
                strHoliday = "海の日"
            End If
        ElseIf (intYear >= 1996) Then
            If (intDay = 20) Then
                strHoliday = "海の日"
            End If
        End If

    '-- 8月 --
    Case 8
        If (intYear >= 2021) Then
            If (intDay = 11) Then
                strHoliday = "山の日"
            End If
        ElseIf (intYear = 2020) Then
            '2020年はオリンピック特措法により「山の日」が 8/10 に移動
            If (intDay = 10) Then
                strHoliday = "山の日"
            End If
        ElseIf (intYear >= 2016) Then
            If (intDay = 11) Then
                strHoliday = "山の日"
            End If
        End If

    '-- 9月 --
    Case 9
        '秋分日の略算式は『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』
        'で紹介されている式です。

        If (intYear <= 1947) Then
            intAutumnalEquinox = 99        '祝日法施行前
        ElseIf (intYear <= 1979) Then
            '(年 - 1983)がマイナスになるので『Fix関数』にする
            intAutumnalEquinox = Fix(23.2588 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1983) / 4))
        ElseIf (intYear <= 2099) Then
            intAutumnalEquinox = Fix(23.2488 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1980) / 4))
        ElseIf (intYear <= 2150) Then
            intAutumnalEquinox = Fix(24.2488 + (0.242194 * (intYear - 1980)) - Fix((intYear - 1980) / 4))
        Else
            intAutumnalEquinox = 99        ' 2151年以降は略算式が無いので不明
        End If

        '第3月曜日(15〜21)と秋分日(22〜24)が重なる事はない
        If (intDay = intAutumnalEquinox) Then  ' 1948〜2150以外は[99]
            strHoliday = "秋分の日"            ' が返るので、必ず≠になる
        Else
            If (intYear >= 2003) Then
                strWeek = (((intDay - 1) \ 7) + 1) & Weekday(ChkDate)
                If (strWeek = "32") Then      '3rd Monday(2)
                    strHoliday = "敬老の日"
                ElseIf (Weekday(ChkDate) = cstTuesday) Then
                    If (intDay = (intAutumnalEquinox - 1)) Then
                        strHoliday = "国民の休日"    '火曜日&[秋分日の前日]
                    End If
                End If
            ElseIf (intYear >= 1966) Then
                If (intDay = 15) Then
                    strHoliday = "敬老の日"
                End If
            End If
        End If

    '-- 10月 --
    Case 10
        strWeek = (((intDay - 1) \ 7) + 1) & Weekday(ChkDate)
        If (intYear >= 2021) Then
            If (strWeek = "22") Then    '2nd Monday(2)
                strHoliday = "スポーツの日"     '2020年より改名
            End If
        ElseIf (intYear = 2020) Then
            '2020年はオリンピック特措法により「スポーツの日」が 7/24 に移動
        ElseIf (intYear >= 2000) Then
            If (strWeek = "22") Then    '2nd Monday(2)
                strHoliday = "体育の日"
            ElseIf (ChkDate = cstSokuireiSeiden_Naruhito) Then    ' (2019/10/22)
                strHoliday = "即位礼正殿の儀"    ' 徳仁親王
            End If
        ElseIf (intYear >= 1966) Then
            If (intDay = 10) Then
                strHoliday = "体育の日"
            End If
        End If

    '-- 11月 --
    Case 11
        If (intDay = 3) Then
            strHoliday = "文化の日"
        ElseIf (intDay = 23) Then
            strHoliday = "勤労感謝の日"
        ElseIf (ChkDate = cstSokuireiSeiden) Then    '(1990/11/12)
            strHoliday = "即位礼正殿の儀' 平成天皇
        End If

    '-- 12月 --
    Case 12
        If (intDay = 23) Then
            If ((intYear >= 1989) And (intYear <= 2018)) Then
                strHoliday = "天皇誕生日' 平成天皇
            End If
        End If
    End Select

    ' ----- 振替休日の判定 (振替休日施行日:1973/4/12) -----
    ' [ 対象日≠祝日/休日 & 対象日=月曜日 ]のみ、前日(=日曜日)を祝日判定する。
    ' 前日(=日曜日)が祝日の場合は”振替休日”となる。
    ' 尚、5月6日の扱いを
    '     「火曜 or 水曜(みどりの日(5/4) or 憲法記念日(5/3)の振替休日)」⇒5月ブロック内で判定済
    '     「月曜(こどもの日(5/5)の振替休日」⇒ここの判定処理で判定
    ' とする事により、ここでの判定対象は『対象日が月曜日』のみ となります。

    If (strHoliday = "") Then
        If (Weekday(ChkDate) = cstMonday) Then
            If (ChkDate >= cstImplementHolidayInLieu) Then
                If (ktHolidayName(ChkDate - 1) <> "") Then  '再帰呼出(月曜のみ)
                    ktHolidayName = "振替休日"
                Else
                    ktHolidayName = ""
                End If
            Else
                ktHolidayName = ""
            End If
        Else
            ktHolidayName = ""
        End If
    Else
        ktHolidayName = strHoliday
    End If
End Function

'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
'_/  CopyRight(C) K.Tsunoda(AddinBox) 2005 All Rights Reserved.
'_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/



以下はテストマクロです。
 Sub Test
 dim MyDate as date
 dim dtmStart as date
 dim dtmEnd as date
 dim strwk1 as string
 dim strwk2 as string
 const cstYear as integer = 2005

   dtmStart = dateserial(cstYear,1,1)
   dtmEnd = dateserial(cstYear,12,31)
   for MyDate = dtmStart to dtmEnd step 1
      strwk1 = ktHolidayName(MyDate)
      if (strwk1 <> "") then
          strwk2 = strwk2 & Chr(13) & Format(MyDate,"yyyy/mm/dd") & "(" & _
                      Choose(Weekday(MyDate),"日","月","火","水","木","金","土") & _
                      ") , " & strwk1
      end if
   next MyDate
   Beep
   MsgBox strwk2
 End Sub






角田 桂一 Mail:addinbox@h4.dion.ne.jp CopyRight(C) 2001 Allrights Reserved.