空腹おやじのログと備忘録

VBA(主にExcel)でいろいろな実験的な事とか、Linuxのコマンドとか設定とかについて忘れないように、あれこれと・・・

VBAによる「祝日判定処理」を「休日判定処理」に拡張してみた

3ヶ月半ほど前の5月28日に、VBAの祝日判定コードを書いたところ思っていた以上にアクセスされているようで、「以外に需要があるものだ」と少々驚いています。(推定で平日30件たらず?ですけど・・・)

そこで、図に乗った空腹おやじは、前回の祝日判定を拡張し、休日判定出来るようにすることにしました。(「休日でなければ・・・」という判定をすれば、営業日とか稼働日の判定にも使えそうです。)

基本は、前回の祝日判定処理を利用して、祝日定義同様に

  • 月日固定の休日
  • 月週曜日固定の休日
  • 曜日固定の休日

を定義する処理を追加し、祝日判定の時と同様に日付指定でBool値判定。

更に、

  • 特定の祝日、休日を除外できるようにする

といったところでしょうか。

クラスモジュール(CCompanyHoliday)のソースは、長いので下の方に・・・

とりあえず祝日定義は、祝日法が変わらなければ、いじる必要が必要ないと思うので
まずは、休日定義を以下の6個のメソッド内で設定してから使ってみてください。

  • getCompanyHolidayInfoW(曜日固定の会社休日情報生成)
  • getCompanyHolidayInfoMD(月日固定の会社休日情報生成)
  • getCompanyHolidayInfoWN(月週曜日固定の会社休日情報生成)
  • getCompanyHolidayInfoMDExclude(月日固定の会社出勤情報生成)
  • getCompanyHolidayInfoWNExclude(月週曜日固定の会社出勤情報生成)

実行例は、こんな感じ。

Public Sub Test(ByVal lYear As Long)

    Dim cch     As CCompanyHoliday
    Dim dt()    As Date
    Dim i As Long

    Set cch = New CCompanyHoliday

    Call cch.getNationalHolidays(lYear, dt)

    For i = 0 To UBound(dt)
        Debug.Print dt(i), cch.getNationalHolidayName(dt(i))
    Next i

    Set cch = Nothing

End Sub

これをイミディエイトウィンドウで実行してみると

call Test(2018)
2018/01/01 元日
2018/01/02 年始休暇
2018/01/03 年始休暇
2018/01/06 会社休日
2018/01/07 会社休日
2018/01/08 成人の日
2018/01/13 会社休日
2018/01/14 会社休日
2018/01/20 会社休日
2018/01/21 会社休日
2018/01/27 会社休日
2018/01/28 会社休日
2018/02/03 会社休日
2018/02/04 会社休日
2018/02/10 会社休日
2018/02/11 建国記念の日
2018/02/12 振替休日
2018/02/17 会社休日
2018/02/18 会社休日
2018/02/24 会社休日
2018/02/25 会社休日
2018/03/03 会社休日
2018/03/04 会社休日
2018/03/10 会社休日
2018/03/11 会社休日
2018/03/17 会社休日
2018/03/18 会社休日
2018/03/21 春分の日
2018/03/24 会社休日
2018/03/25 会社休日
2018/03/31 会社休日
2018/04/01 会社休日
2018/04/07 会社休日
2018/04/08 会社休日
2018/04/14 会社休日
2018/04/15 会社休日
2018/04/21 会社休日
2018/04/22 会社休日
2018/04/28 会社休日
2018/04/30 振替休日
2018/05/03 憲法記念日
2018/05/04 みどりの日
2018/05/05 こどもの日
2018/05/06 会社休日
2018/05/12 会社休日
2018/05/13 会社休日
2018/05/19 会社休日
2018/05/20 会社休日
2018/05/26 会社休日
2018/05/27 会社休日
2018/06/02 会社休日
2018/06/03 会社休日
2018/06/09 会社休日
2018/06/10 会社休日
2018/06/16 会社休日
2018/06/17 会社休日
2018/06/18 特別休日
2018/06/23 会社休日
2018/06/24 会社休日
2018/06/30 会社休日
2018/07/01 会社休日
2018/07/07 会社休日
2018/07/08 会社休日
2018/07/14 会社休日
2018/07/15 会社休日
2018/07/16 海の日
2018/07/21 会社休日
2018/07/22 会社休日
2018/07/28 会社休日
2018/07/29 会社休日
2018/08/04 会社休日
2018/08/05 会社休日
2018/08/11 山の日
2018/08/12 お盆休暇
2018/08/13 お盆休暇
2018/08/14 お盆休暇
2018/08/15 お盆休暇
2018/08/16 お盆休暇
2018/08/17 お盆休暇
2018/08/18 お盆休暇
2018/08/19 会社休日
2018/08/26 会社休日
2018/09/01 創業記念日
2018/09/02 会社休日
2018/09/08 会社休日
2018/09/09 会社休日
2018/09/15 会社休日
2018/09/16 会社休日
2018/09/17 敬老の日
2018/09/22 会社休日
2018/09/23 秋分の日
2018/09/24 振替休日
2018/09/29 会社休日
2018/09/30 会社休日
2018/10/06 会社休日
2018/10/07 会社休日
2018/10/08 体育の日
2018/10/13 会社休日
2018/10/14 会社休日
2018/10/20 会社休日
2018/10/21 会社休日
2018/10/24 特別休日
2018/10/25 特別休日
2018/10/27 会社休日
2018/10/28 会社休日
2018/11/03 文化の日
2018/11/04 会社休日
2018/11/10 会社休日
2018/11/11 会社休日
2018/11/17 会社休日
2018/11/18 会社休日
2018/11/23 勤労感謝の日
2018/11/24 会社休日
2018/11/25 会社休日
2018/12/01 会社休日
2018/12/02 会社休日
2018/12/08 会社休日
2018/12/09 会社休日
2018/12/15 会社休日
2018/12/16 会社休日
2018/12/22 会社休日
2018/12/23 天皇誕生日
2018/12/24 振替休日
2018/12/29 年末休暇
2018/12/30 年末休暇
2018/12/31 年末休暇


クラスモジュール(CCompanyHoliday)のソースは、▶こちらをクリックで展開します。(注:1055行ありますので・・・ご注意下さい。m(_ _)m)
2021/4/11
都合により、こちら に移動しました。

CCompanyHoliday.cls のみ
https://github.com/Z1000R/determining-and-retrieving-holidays/blob/main/Source/CCompanyHoliday.cls

その他諸々を含めて一式
github.com

お約束

掲載したコードの使用については、特に制限は設けません。MITライセンスとします。
ご自由にお使い下さい。
使用にあたって、私への連絡等は不要です。

ただし、使用した結果、何らかのトラブル、損害、その他諸々の事象が発生しても、私は一切関与しません。
ソースコードを組み込んだ方が責任を取れる範囲内で使って下さい。

バグ、要望、気が付いた事などあれば、コメントしていただければと思います。

マウントできなくなったHDDから、testdiskを使用して、ファイルをサルベージしてみた

USB接続で使用していた4TBのHDDが、突然使用できなくなりました。
マウントできないと・・・
f:id:Z1000S:20180702221411p:plain

根本的な原因は不明なのですが、ラベルが書き換わって、openSUSE-Leapとなっていましたし、
中途半端に、ddコマンドが実行されたような感じでしょうか?
openSUSEは、インストール用としてUSBメモリに書き込むために以前使ったことはありますが
現在は、内蔵HDDには残っていません。

f:id:Z1000S:20180702220751j:plain

主にバックアップ用として使用していたので
いろいろと大切なファイル(そう、あんなファイルやこんなファイル・・・)を保存していたので
困ってしまいました。

唯一救いだったのが、OSのインストールされたHDDではなく
外付けのHDDだったので、不要な書き込みによる上書きの心配が少なかったことでしょうか。

諦めてフォーマットしてしまおうかと思ってみたものの
少しくらいは悪あがきしてみて、駄目なら諦めようと調べてみると
testdiskというツールがあるらしく、それを使ってみることにした。

HDDの情報が書き換わったPC(Manjaro Linux)でサルベージするのも嫌だったので
別のPC(Antergos)で作業することに。

pacmanで検索すると、testdiskが見つかったので、即インストール。

端末から、コマンドを入力して開始。
f:id:Z1000S:20180702221033p:plain

最初にログの作成方法について聞いてきた。
初めてなので、新規にログを作成するので、「Create」が選択された状態でEnter
(ログは、自分のHOMEディレクトリに作成されました。 /home/z1000)
f:id:Z1000S:20180702221243p:plain

次に認識されたHDDのリストが表示されるので、対象となるHDDを選択して
[ Proceed ]を選択して、Enter
f:id:Z1000S:20180702221756p:plain

次は、パーティションテーブルの種類。
今回のLinuxの場合には、[ Intel ]を選べばOKなようです。
f:id:Z1000S:20180702222029p:plain

事前の準備が住んだところで、まずは分析
[ Analyse ]を選択して、Enter
f:id:Z1000S:20180702222150p:plain

現状で、OSが認識している状況が表示される(?)ようです。
[ Quick Search ]を選択して、Enter
f:id:Z1000S:20180702222245p:plain

そうすると、以前の状況らしきものが見えてきた。
f:id:Z1000S:20180702222553p:plain

キーボードから「P」を入力すると、ファイルリストが表示されるようです。
f:id:Z1000S:20180702222726p:plain
2018/7/3 修正
赤い文字のファイルやディレクトリは、復元できないものなのかもしれない。
赤い文字のファイルも復元はできるようです。


↑↓で、ディレクトリやファイルを選択でき、
←→で、ディレクトリの親や子に移動できるようです。
f:id:Z1000S:20180702223326j:plain

サルベージしたいファイルやディレクトリを選択し、
キーボードの「C」を押下すると、コピー先を聞いてきます。
f:id:Z1000S:20180702223621j:plain

あとは、移動先を選択し、Enterを押下すればコピーが始まります。
f:id:Z1000S:20180702223842j:plain

選択したファイルは、階層付きでコピーされました。
f:id:Z1000S:20180702224441j:plain

この調子で、他のファイルも・・・

2018/7/3 追記
USBメモリのファイルを削除して、同様に操作したら、
削除したファイルを復元できました。
復元されたファイルの所有者、グループはrootでした。
ファイル名によっては、元のファイル名を復元できない場合もあるようです。
(省略形のような名前で復元されたりする場合があるようです。)

ExcelのVBAで使えるDLLを、C++(Visual Studio 2017)で作る。・・・その2

次回予告までしておきながら、他にVBA関係の記事を書いていたこともあり、既に2ケ月以上が過ぎ、
「いつ頃までに、まとめられるかは、不明・・・」の記載通りになってしまった。

前回も書きましたけど、64bit版のVBAではどうなるかわかりませんので!!!

今回の内容は次の通り。

  1. 受け渡しするデータの型について
  2. 処理する値を渡せるようにすること
  3. 値渡しと参照渡しについて
  4. 処理した結果や値を返してもらえるようにすること
  5. 数値型の場合の受け渡しの例


受け渡しするデータの型について

とりあえず必要なのは、VBAC++のデータ型の対応。
VBA独自の型は、C++に渡せないし、逆にC++にしかない型は、VBAが受け取れない。
(条件付きであれば、例外もあるけど・・・)
VBAの主な型を中心に対応を見てみると次のような感じ。

VBAの型 C++の型 備考
Byte unsigned char
BYTE
Integer short
SHORT
Long int
long
INT
LONG
Single float
Double double
Boolean BOOL
C++の型 VBAの型 備考
HANDLE Long
char
CHAR
Byte 最上位ビットがOFFならばそのまま使用可
unsigned short
WORD
Integer 最上位ビットがOFFならばそのまま使用可
unsigned int
unsigned long
UINT
ULONG
DWORD
Long 最上位ビットがOFFならばそのまま使用可
VBAにあってC++にない型(抜粋)
Currency
Date
Decimal
String
Object
Variant
C++にあってVBAにない型(抜粋)
WCHAR
LONGLONG
ULONGLONG

VBAのString型に対応するC++の型はありません。
ちょっと特殊です。データの受け渡しにはchar型のポインタまたは、BSTR型を使用します。
これについては、次回(?)にでも・・・

処理する値を渡せるようにすること

DLLに何らかのデータ処理をしてもらうためには、必要なデータを渡してあげないと出来ません。
データはVBAの関数と同様にパラメータに引数を渡します。
ただ、C++VBAでは、構文が違うので予め覚えておく必要があります。

値渡しと参照渡しについて

値渡し
引数のアドレスをプロシージャに渡すのではなく引数の値を渡す方法。
VBAでは、ByValを指定する事により値渡しとなる。
参照渡し
引数の値をプロシージャに渡すのではなく引数のアドレスを渡す方法。
VBAでは、デフォルトで参照渡しである。明示的に指定する場合には、ByRefを指定する。

C++の場合

値渡し
データ型の後ろに変数を指定する。
void doAnything(int hoge); intデータ型で、hoge変数
値渡し
データ型の後ろに"*"を付けその後ろに変数を指定する。(ポインタですな。)
void doSomething(long* fuga); longデータ型で、fuga変数

処理した結果や値を返してもらえるようにすること

値を返してもらう方法は、大きく分けて2つ。
一つは、関数の復帰値による方法。
これは、VBAでいえば、ファンクションプロシージャによる復帰値で結果を得る方法と同じ。
C++の場合には、関数名の前に復帰値のデータ型を指定する。
復帰値の型 関数名(パラメータリスト)
もう一つは、渡したパラメータにデータを入れてもらい、返してもらう方法。
こちらは、VBAでいえば、パラメータにByRefを指定し、返してもらう方法と同じ。
どちらを使うかは、状況に応じて使い分ければよろしいかと。
場合によっては、両方というのもありです。

数値型の場合の受け渡しの例

VBAからLongの値を渡して、2倍した結果を返してもらう「GetNumberI」という関数と、
300倍した値を返してもらう「GetNumberI2」を作ってみます。
GetNumberIは、パラメータを値渡しして、復帰値で結果をもらいます。
GetNumberI2は、パラメータを参照渡しし、そのパラメータ値を変更して返してもらいます。

前回のファイルに、書き加えていきます。

まず、ヘッダファイル(AccessibleFromVBA.h)

#pragma once

extern "C"
{
#define ACCESSIBLEFROMVBA_API __declspec(dllexport) 

	ACCESSIBLEFROMVBA_API void WINAPI DoNothing();

	ACCESSIBLEFROMVBA_API int WINAPI GetNumberI(int i);

	ACCESSIBLEFROMVBA_API void WINAPI GetNumberI2(int* pi);
}

f:id:Z1000S:20180627100359j:plain

次に、ソースファイル(AccessibleFromVBA.cpp)

#include "stdafx.h"
#include "AccessibleFromVBA.h"


ACCESSIBLEFROMVBA_API void WINAPI DoNothing()
{
	return;
}

//int型の値を受け取って、int型の復帰値を返す(VBAのファンクションプロシージャ相当)
ACCESSIBLEFROMVBA_API int WINAPI GetNumberI(int i)
{
	return i * 2;
}

//int型の値を受け取って、内部で値を変更して返す(VBAでパラメータをByRef で受け渡しするイメージ)
ACCESSIBLEFROMVBA_API void WINAPI GetNumberI2(int* pi)
{
	*pi *= 300;

	return;
}

f:id:Z1000S:20180627100406j:plain

最後に、モジュール定義ファイル(AccessibleFromVBA.def)

LIBRARY AccessibleFromVba

EXPORTS
	DoNothing
	GetNumberI
	GetNumberI2

f:id:Z1000S:20180627100410j:plain
全て追加したら、プロジェクトをビルドします。

========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========

と表示されればOK。
f:id:Z1000S:20180627100414j:plain

呼び出すExcel側は、

Private Declare Function GetNumberI Lib "C:\Datas\MyDatas\Developer\VisualStudioComunity2017\DllForVBA\ForTest\AccessibleFromVBA.dll" (ByVal l As Long) As Long

Private Declare Sub GetNumberI2 Lib "C:\Datas\MyDatas\Developer\VisualStudioComunity2017\DllForVBA\ForTest\AccessibleFromVBA.dll" (ByRef l As Long)

呼び出してみる

Public Sub DllCallTest2()

    Dim lValue  As Long
    Dim lResult As Long

    lValue = 1000

    lResult = GetNumberI(lValue)

    Debug.Print "GetNumberI:", lValue, lResult

    Debug.Print ""

    Debug.Print "GetNumberI2(Before):", lValue

    Call GetNumberI2(lValue)

    Debug.Print "GetNumberI2(After ):", lValue

End Sub

実行結果は、

call DllCallTest2
GetNumberI: 1000 2000


GetNumberI2(Before): 1000
GetNumberI2(After ): 300000

f:id:Z1000S:20180713081606j:plain

当てにならない次回予告

とりあえず、数値の受け渡しは出来たので、次は、

  • 文字列
  • 配列
  • 構造体

の受け渡しあたりをまとめられたらいいなぁ~


z1000s.hatenablog.com
z1000s.hatenablog.com
z1000s.hatenablog.com
z1000s.hatenablog.com
z1000s.hatenablog.com
z1000s.hatenablog.com
z1000s.hatenablog.com

VBAによる祝日判定および祝日取得(改正東京五輪・パラリンピック特別措置法 対応)

2018年6月13日、参院本会議で可決、成立しました。

これに伴って、2020年の祝日が移動するものが出てきたようなので、先日公開した祝日判定処理を更新しました。
また、2020年からは「体育の日」が「スポーツの日」になるそうなので、合わせて対応済みです。

まぁ、祝日の定義の部分を変えただけなんですけどね。
処理内容は全く変えないで、元になる祝日データだけいじればいいので、祝日の追加、廃止、変更等のメンテナンスは楽ですよ。

ソース

実行例

2019年から2021年の7月から10月の祝日を出力した結果が以下の通り。

----- 2019 -----
2019/07/15 海の日
2019/08/11 山の日
2019/08/12 振替休日
2019/09/16 敬老の日
2019/09/23 秋分の日
2019/10/14 体育の日

----- 2020 -----
2020/07/23 海の日
2020/07/24 スポーツの日
2020/08/10 山の日
2020/09/21 敬老の日
2020/09/22 秋分の日

----- 2021 -----
2021/07/19 海の日
2021/08/11 山の日
2021/09/20 敬老の日
2021/09/23 秋分の日
2021/10/11 スポーツの日

【VBA / Excel】祝日休日の判定、取得用データを生成し、実際に判定、取得してみる

この記事では、予め用意された祝日テーブルを使用するのではなく、
クラスモジュール内で、祝日テーブルを自前で生成し、Dictionary に格納して判定処理を行っています。
祝日の定義は、クラスモジュール内に、汎用性を考慮した状態でハードコーディングしてあります。
このため、法の変更等により、祝日が変わらなければ、このまま使用できます。
別途、祝日テーブルを用意する必要はありません。

2018/9/10 追記
この記事は、祝日(振替休日等を含む)を判定の対象にしていますが、日曜日や年末年始の休み等は判定対象外です。
これらの休日も判定対象に含めたい場合には、以下の記事をあわせて参照してみて下さい。
z1000s.hatenablog.com


2018/6/14 追記
この記事には、2018/6/13の改正東京五輪パラリンピック特別措置法が参院本会議での可決に伴って、更新された記事があります。
z1000s.hatenablog.com

2019/5/23 追記
Googleで検索して来る方が多いようですが、中にはこのページが本来の目的ではない方もいるかもしれないので、とりあえず、「こんなページもあるよ」ということで載せておきます。
z1000s.hatenablog.com
z1000s.hatenablog.com


目次みたいなもの


Excelで祝日判定をしたい」というと、「祝日データを用意して、それを・・・」とお決まりの文言が出てくるのが一般的です。
では、その祝日データはどうすれば用意できるのでしょうか?

ここのように、期間を指定して生成してくれるようなところもあるようです。

が、必要なデータが変わるたびにサイトにアクセスしてというのも面倒です。
となれば、「自分で作ってしまえ作れるようにしてしまえ」となりました。

以上



???普通ならそうはならない???
まぁ、いいじゃないですか。私がそう思ったんだから。
それに、ここで終わったら、ただの落書きで終わってしましますよ。


そろそろ本題に。

まず、処理するに当たって祝日を分類してみる。カッコ内は例。

  1. 月、日が固定のもの(元日:1月1日)
  2. 月、第N ○曜日が固定のもの(成人の日:1月第2月曜日)
  3. 月は固定だが、日が可変のもの(春分の日:3月19〜22日)
  4. 月、日が定まっておらず、他の祝日などに依存するもの(振替休日、国民の休日

1、2項は簡単に求められる。
3項は、計算式があるのでこれも問題なし。
4項は、他の祝日に依存するため、単独では求められない。予め1〜3項の祝日がわかっている必要がある。(或いは、その都度依存する日の状態を確認するか。)

では具体的にどうすれば求められるか、簡単(?)かもしれない解説。
前提条件として、データはDate型で保持するものとします。

1.月、日が固定のもの

VBA では、DateSerial 関数を使用すると、年、月、日を指定してDate 型の値を取得できます。

DateSerial( year, month, day )

DateSerial 関数については、こちら

2.月、第N ○曜日が固定のもの

指定された月の1日の曜日がわかれば、1日以降の最初の指定された曜日(第1○曜日)へのオフセット値(何日補正すればよいか)がわかります。
それがわかれば、7の倍数を加算することで求められます。

まず、指定月の1日を求めるのは、1項で登場したDateSerial 関数

DateSerial( year, month, 1 )

と日に「1」を指定すればOK。

次にその曜日
曜日は、Weekday 関数を使用します。

Weekday( date , [ firstdayofweek ] )

dateに、上で求めた1日の日付データを渡します。
firstdayofweekは省略可能です。今回は使用しません。
そうすると、指定した日付によって1〜7の値が返ってきます。

定数 説明
vbSunday 1 日曜日
vbMonday 2 月曜日
vbTuesday 3 火曜日
vbWednesday 4 水曜日
vbThursday 5 木曜日
vbFriday 6 金曜日
vbSaturday 7 土曜日

これを書いている2018年5月の場合を考えてみます。
第2週までのカレンダーは、以下の通りです。

1 2 3 4 5
6 7 8 9 10 11 12

最初の曜日までの日数は、以下のようになります。

曜日 指定曜日の日付 1日から指定曜日までの日数
日曜日 6 5
月曜日 7 6
火曜日 1 0
水曜日 2 1
木曜日 3 2
金曜日 4 3
土曜日 5 4

で、曜日を使って「指定曜日までの日数」をどうやって求めるかというと
前述の曜日の定数を使って「指定曜日」 から 「1日の曜日」を引きます。
ただし、「指定曜日」が「1日の曜日」より前の場合、結果が負の値となるのでその場合には7を加えます。

5月1日は火曜日なので、vbTuesday ===> 3
例えば、第1金曜日なら、vbFriday ===> 6
なので、6 - 3 = 3 となります。

第1日曜日なら、vbSunday ===> 1
なので、1 - 3 = -2 となりますが、結果が負なので、+7 して
-2 + 7 = 5 となります。

この値が求められれば、次は1日の日付に加算を行います。
日付の加減算は、DateAdd 関数を使用します。

DateAdd(interval, number, date)

intervalには、日数の計算を行うので、"d" を指定します。
numberには、上記の計算で求めた値を指定します。
dateには、1日の日付データを指定します。

最初の曜日であれば、これで良いのですが2回め以降の曜日の場合、更に7の倍数を加算する必要があります。
第2曜日であれば、+7
第3曜日であれば、+14
第4曜日であれば、+21
第5曜日であれば、+28
となるので、第N曜日の場合
(N ー 1)*7
を加算すれば良いことになります。

最終的には、以下のようなプロシージャにより求められます。

Public Function getNthWeeksDayOfWeek(ByVal lYear As Long, _
                                      ByVal lMonth As Long, _
                                      ByVal lNth As Long, _
                                      ByVal lDayOfWeek As VbDayOfWeek) As Date

    Dim dt1stDate       As Date
    Dim lDayOfWeek1st   As Long
    Dim lOffset         As Long

    '指定年月の1日を取得
    dt1stDate = DateSerial(lYear, lMonth, 1)

    '1日の曜日を取得
    lDayOfWeek1st = Weekday(dt1stDate)

    '指定日へのオフセットを取得
    lOffset = lDayOfWeek - lDayOfWeek1st

    If lDayOfWeek1st > lDayOfWeek Then
        lOffset = lOffset + 7
    End If

    lOffset = lOffset + 7 * (lNth - 1)

    getNthWeeksDayOfWeek = DateAdd("d", lOffset, dt1stDate)

End Function

ただし、N >= 5を指定した場合、日付が翌月になる場合がありますので、注意が必要です。

Weekday 関数については、こちら
DateAdd 関数については、こちら

3.月は固定だが、日が可変のもの

これは、春分の日秋分の日が該当。
Wikipediaによると
春分の日は、3月19~22日のいずれか。
秋分の日は、22~24日のいずれか。
となっている。
一般に、

'春分の日
Int(20.8431 + 0.242194 * (- 1980)) - Int((- 1980) / 4)
'秋分の日
Int(23.2488 + 0.242194 * (- 1980)) - Int((- 1980) / 4)

という計算で求められるようです。
1980年以降に限定すれば、以下の内容でもOK。
というか、こうしたかったんだけれど、1979年以前の場合、
演算子の結果が、Fix 関数と同等になり、Int 関数とは結果が変わってしまうため
If で振り分ける等の必要が生じてしまうので、上記の式をそのまま使用することにしました。

'春分の日
Int(20.8431 + 0.242194 * (- 1980)) - (- 1980) \ 4
'秋分の日
Int(23.2488 + 0.242194 * (- 1980)) - (- 1980) \ 4

ちなみに、¥演算子を使用した場合は、内部で整数演算が行われるが、
/演算子の場合、整数同士の演算であっても、内部では浮動小数点数で演算が行われます。

4.月日が定まっておらず、他の祝日などに依存するもの

4.1 振替休日

1973年の国民の祝日に関する法律が改正されたことにより制定された。これにより祝日(国民の祝日)が日曜日の場合、その翌日となる月曜日が振替休日となった(ハッピーマンデー制度の法律と同じ)。1973年の天皇誕生日(4月29日)が日曜日で、同年4月30日が最初の適用日となった。

当初は祝日が2日以上連続することがなかったため、「国民の祝日の日曜日の翌日の月曜日」としていた。しかし2005年の国民の祝日に関する法律の改正(2007年施行)で、4月29日が「昭和の日」となり、「みどりの日」が4月29日から5月4日へ変更。5月3日から5月5日まで祝日が3日連続することになり、その直後の国民の祝日の日曜日の翌日の月曜日以降の国民の祝日でない祝日の翌日」を休日とすることと改められ振替先が月曜日固定ではなくなった。

振替休日 - Wikipedia

ということなので、
祝日が日曜日であった場合、適用された年から判断し、その翌日または、それ以降で最初の祝日でない日を求めればOK。
2007年以降では、当然ながらこの日が月曜日とは限りません。
2015年5月3日の憲法記念日の振替休日は、6日の水曜日でした。
 5月3日(日):憲法記念日
 5月4日(月):みどりの日
 5月5日(火):こどもの日
 5月6日(水):5月3日の振替休日

4.2 国民の休日

前後が祝日である平日は、国民の休日となり、休日となる。

国民の休日 - Wikipedia

こちらは、翌々日まで確認が必要なので、要件は振替休日より複雑。

  1. 最初の祝日が月曜日から金曜日の間にあること。
    1. 最初の祝日が日曜日の場合、翌日は振替休日となるので、2項を満足しない。
    2. 最初の祝日が土曜日の場合、翌日は日曜日となるので、平日ではない。
  2. 最初の祝日の翌日が、平日であること。(祝日でなく、休日でもないこと。)
  3. 最初の祝日の翌々日が、祝日であること。

これらの条件を満たした時、最初の祝日の翌日が「国民の休日」となる。

2項、3項の祝日は、年によって日付が変動する祝日であり、「移動祝日」または「移動祝祭日」と呼ぶそうです。

最終的なコード

VBAのクラスとして作成しました。
▶クリックでソースを展開/縮小
2021/4/11
都合により、
VBAによる「祝日判定処理」を「休日判定処理」に拡張してみた - 空腹おやじのログと備忘録
と、コードを統合した上で、
こちら に移動しました。

CCompanyHoliday.clsのみ
https://github.com/Z1000R/determining-and-retrieving-holidays/blob/main/Source/CCompanyHoliday.cls

その他諸々を含めて一式
github.com

パブリックメソッド一覧

isNationalHoliday(ByVal dtDate As Date) As Boolean

指定日が国民の祝日(休日)か?

引 数 IN/OUT 内容
dtDate As Date IN 判定したい日付
復帰値 内容
True 国民の祝日(休日)である。
False 国民の祝日(休日)ではない。
isNationalHoliday2(ByVal dtDate As Date, ByRef sHolidayName As String) As Boolean

指定日が国民の祝日(休日)か?そうであれば、その祝日名を合わせて返す

引 数 IN/OUT 内容
dtDate As Date IN 判定したい日付
sHolidayName As String OUT 祝日名
復帰値 内容
True 国民の祝日(休日)である。
False 国民の祝日(休日)ではない。
getNationalHolidays(ByVal lYear As Long, ByRef dtHolidays() As Date) As Long

指定年の国民の祝日を配列に格納して返す

引 数 IN/OUT 内容
lYear As Long IN 取得したい年
dtHolidays() As Date OUT 指定された年の国民の祝日
復帰値
国民の祝日の件数
getNationalHolidayName(ByVal dtHoliday As Date) As String

指定日の国民の祝日名を返す

引 数 IN/OUT 内容
dtHoliday As Date IN 日付
復帰値
指定された日付の国民の祝日

指定された日付が国民の祝日でない場合、復帰値は長さ0の文字列となる。

reInitialize(ByVal lLastYear As Long)

指定年までの祝日データが生成されていなければ、追加生成する。

引 数 IN/OUT 内容
lLastYear As Long IN 生成したい最終年

現在の何年までのデータが生成されているかは、後述のInitializedLastYearプロパティで取得できる。

パブリックプロパティ

InitializedLastYear() As Long

何年までの国民の祝日データが生成されているか
(読み取り専用)

使い方と実行例

クラス名は、CNationalHoliday としています。
使用する前に、Newを付けて、インスタンスを生成して下さい。
(そのタイミングで、デフォルトで現在の年から5年後の年末までの祝日を内部で生成します。)
その後に、必要なメソッドを呼び出します。

日付を指定して、祝日判定をして、祝日名を取得する
Public Sub Test1()

    Dim cnh     As New CNationalHoliday
    Dim dt      As Date
    Dim sHolidayName As String

    dt = #8/11/2015#
    Debug.Print Format$(dt, "yyyy/mm/dd"), cnh.getNationalHolidayName(dt), cnh.isNationalHoliday2(dt, sHolidayName)

    dt = #8/11/2016#
    Debug.Print Format$(dt, "yyyy/mm/dd"), cnh.getNationalHolidayName(dt), cnh.isNationalHoliday2(dt, sHolidayName)

    dt = #8/12/2018#
    Debug.Print Format$(dt, "yyyy/mm/dd"), cnh.getNationalHolidayName(dt), cnh.isNationalHoliday2(dt, sHolidayName)

    dt = #8/12/2019#
    Debug.Print Format$(dt, "yyyy/mm/dd"), cnh.getNationalHolidayName(dt), cnh.isNationalHoliday2(dt, sHolidayName)

    dt = #2/23/2020#
    Debug.Print Format$(dt, "yyyy/mm/dd"), cnh.getNationalHolidayName(dt), cnh.isNationalHoliday2(dt, sHolidayName)

    Set cnh = Nothing

End Sub

実行結果

call Test1
2015/08/11                  False
2016/08/11    山の日        True
2018/08/12                  False
2019/08/12    振替休日      True
2020/02/23    天皇誕生日    True
年を指定して、祝日および祝日名を取得する
Public Sub Test2(ByVal lYear As Long)

    Dim cnh     As New CNationalHoliday
    Dim dt()    As Date
    Dim i As Long

    Call cnh.getNationalHolidays(lYear, dt)

    For i = 0 To UBound(dt)
        Debug.Print dt(i), cnh.getNationalHolidayName(dt(i))
    Next i

    Set cnh = Nothing

End Sub

実行結果

call Test2(2018)
2018/01/01    元日
2018/01/08    成人の日
2018/02/11    建国記念の日
2018/02/12    振替休日
2018/03/21    春分の日
2018/04/29    昭和の日
2018/04/30    振替休日
2018/05/03    憲法記念日
2018/05/04    みどりの日
2018/05/05    こどもの日
2018/07/16    海の日
2018/08/11    山の日
2018/09/17    敬老の日
2018/09/23    秋分の日
2018/09/24    振替休日
2018/10/08    体育の日
2018/11/03    文化の日
2018/11/23    勤労感謝の日
2018/12/23    天皇誕生日
2018/12/24    振替休日
祝日データを、デフォルトの5年後より後の分も生成する
Public Sub Test3()

    Dim cnh As CNationalHoliday
    Dim dt  As Date
    Dim i As Long

    Set cnh = New CNationalHoliday

    Debug.Print "Before reInitialize", cnh.InitializedLastYear

    cnh.reInitialize 2030

    Debug.Print "After reInitialize", cnh.InitializedLastYear

    Set cnh = Nothing

End Sub

実行結果

call Test3
Before reInitialize          2023 
After reInitialize           2030 

お約束

掲載したコードの使用については、特に制限は設けません MITライセンスとします。
ご自由にお使い下さい。
使用にあたって、私への連絡等は不要です。

ただし、使用した結果、何らかのトラブル、損害、その他諸々の事象が発生しても、私は一切関与しません。
使用する方ソースコードを組み込んだ方が責任を取れる範囲内で使って下さい。(2018/9/9 一部修正)

バグ、要望、気が付いた事などあれば、コメントしていただければと思います。

参考にしたサイト

秀丸で、選択行の行頭に文字を挿入するマクロ

先日、人力検索はてなで、
q.hatena.ne.jp
に回答して、ベストアンサーを頂いたのですが
ベースになった物があって、C++のソースを編集する際に、

  • 行コメントの追加
  • 既存の行を改修してコメント化

するために以前作ったもの(下記)でした。
(今回の件で、ちょっとしたバグを発見して修正したけど・・・)

あちらにアップしたものは、コメント削除したものなので、わかりにくかったかも。

$comment_prefix = "//";

//範囲選択されているか
if ( selecting == 1 )
{
	//範囲選択されていたら解除
	escape;

	//選択開始行
	#TargetLine = seltopy + 1;

	//選択終了行
	if ( selendx == 0 )
	{
		//選択終了行のカーソル位置が行先頭なら、その行はコメント化しない
		#EndLine    = selendy;
	}
	else
	{
		#EndLine    = selendy + 1;
	}

	//選択開始行に移動
	movetolineno 1, seltopy + 1;
}
else
{
	//選択開始行
	#TargetLine = lineno;

	//選択終了行
	#EndLine    = lineno;
}

//最終行に移動
gofileend;

//最終行取得
#FileEndLine = lineno;

//元の行に戻る
movetolineno 1, #TargetLine;

while ( #TargetLine != #EndLine + 1 )
{
	//行先頭に移動
	golinetop;

	//コメント化
	insert $comment_prefix;

	//処理行をインクリメント
	#TargetLine = #TargetLine + 1;

	if ( #TargetLine > #FileEndLine )
	{
		break;
	}

	//1行下へ移動
	movetolineno 1, #TargetLine;
}