VBA

【VBA】曜日休み、祝日を考慮して第一営業日を取得する方法(独自の休日にカスタマイズも可能)

記事内に商品プロモーションを含む場合があります

このページでわかること

曜日休みや祝日を加味して第一営業日を取得するプロシージャを紹介します。
独自の休日にカスタマイズする方法もご紹介します。

覚えること
  1. 土日など特定の曜日を考慮して第一営業日を取得する方法

  2. 特定の曜日と祝日を考慮した第一営業日を取得する方法

  3. 独自の休日にカスタマイズして第一営業日を取得する方法

土日など特定の曜日のみ休みバージョン

特定の曜日は割りと簡単です。
書式設定で日付から曜日を簡単に取得できるからです。

曜日を得るためには

Format(日付 , “ddd”):Friなど英語の三文字
Format(日付 , “dddd”):Fridayなど英語のフル
Format(日付 , “aaa”):金など日本語一文字
Format(日付 , “aaaa”):金曜日など日本語フル

お好みでいいと思いますが、
今回は日本語一文字でやってみます。

2021年の5月の第一営業日(土日休みの場合)を取得してみます。
割とどうとでもなりますがこんな感じを考えてみました。

曜日休みをdayOff1とdayOff2の変数に入力し
Do Loop文で特定の日付が曜日休みじゃなくなるまで日付を加算します。

Dim myYear As Long '特定の年
Dim myMonth As Long '特定の月
Dim mydate As Date '特定の年、月の1日
Dim myWeek As String '特定の日付の曜日
Dim dayOff1, dayOff2 As String '休みの曜日

'休みの設定
dayOff1 = "土"
dayOff2 = "日"

myYear = 2021
myMonth = 5
mydate = myYear & "/" & myMonth & "/" & 1
myWeek = Format(mydate, "aaa")

'曜日が土か日の場合、一日追加する
Do While myWeek = dayoff1 Or myWeek = dayoff2
    mydate = DateAdd("d", 1, mydate)
    myWeek = Format(mydate, "aaa")
Loop

MsgBox ("日付は:" & mydate & vbCrLf & _
        "曜日は:" & myWeek)
        
End Sub

特定の曜日と祝日を考慮したバージョン

恐らくこれが一番複雑です(もっといい案あるかもですが・・)

二つの指標をクリアさせる必要があります。

  • 国民の祝日の日付ではない
  • 休日の曜日ではない

私の戦略は

  1. 祝日のテーブルを作る
  2. 特定の日付が祝日のテーブルにない、かつ、曜日休みでない という状態までDo Loop処理で日付加算を行う

国民の祝日はこちらを参考にしました。

こんな感じでエクセルに表としてまとめました。
プログラムを作っていきましょう。

Sub 祝日を含む第一営業日()

Dim myYear As Long '特定の年
Dim myMonth As Long '特定の月
Dim myDate As Date '特定の年、月の1日
Dim myWeek As String '特定の日付の曜日
Dim table As ListObject '祝日テーブル
Dim r As Range 'For each文で使うレンジオブジェクト
Dim fndRng As Range '国民の祝日かどうか探索
Dim dayOff1, dayOff2 As String '休みの曜日


'休みの設定
dayOff1 = "土"
dayOff2 = "日"

'どの月を対象とするか設定
myYear = 2021
myMonth = 5

'対象となる月の1日をmyDateとする。
myDate = myYear & "/" & myMonth & "/" & 1

'myDateの曜日を取得
myWeek = Format(myDate, "aaa")

'祝日テーブルの変数代入
Set table = ActiveSheet.ListObjects(1)

'祝日テーブルからmyDateの日付を探索
Set fndRng = table.ListColumns("日付").DataBodyRange.Find(what:=Format(myDate, "yyyy/mm/dd"), lookat:=xlWhole, LookIn:=xlValues)

'fndRngがNothing(=祝日ではない)かつ曜日休みでないという状態まで日付を加算
Do Until fndRng Is Nothing And myWeek <> dayOff1 And myWeek <> dayOff2
    myDate = DateAdd("d", 1, myDate)
    myWeek = Format(myDate, "aaa")
    Set fndRng = table.ListColumns("日付").DataBodyRange.Find(what:=Format(myDate, "yyyy/mm/dd"), lookat:=xlWhole, LookIn:=xlValues)
Loop


MsgBox ("日付は:" & myDate & vbCrLf & _
        "曜日は:" & myWeek)

End Sub

設定すればどの年のどの月でも対応できるはずです。
プロシージャにもありますが、以下の3つを設定しましょう。

  • dayOff1とdayOff2の変数に休みの曜日を入力
  • myYearとmyMonthの変数に対象となる年と月を入力
  • 休日テーブルを作成

2021年5月で休みを土日に設定してみました。
1日は土曜日、2日は日曜日、3日は憲法記念日、4日はみどりの日、5日はこどもの日となり、第一営業日は6日の木曜日となります。
こんな感じです。

2021年11月で休みを月火としてみました。
1日は月曜、2日は火曜、3日は文化の日となり、
第一営業日は4日の木曜となります。

独自の休みにカスタマイズするバージョン

会社独自の休みで運用したい場合もあると思います。

その場合は休日カレンダーを作り、
フィルタリングしていくのが割りと簡単な気がします。

こんな感じでテーブルを作り、休みに「〇」を付けていきます。

例えば、普段の休みを集約して、年始にものすごく休むカレンダーを作ったとします。
この場合は以下のようなプロシージャで第一営業日を取得することができます。

Sub 日付カスタマイズ()

Dim myYear As Long '特定の年
Dim myMonth As Long '特定の月
Dim myDate As Date '特定の年、月の1日
Dim myWeek As String '特定の日付の曜日
Dim table As ListObject '休日テーブル
Dim Row, Clm As Long 'テーブルから日付を取得するための行、列の取得
Dim r As range 'For each文で使うレンジオブジェクト


'どの月を対象とするか設定
myYear = 2021
myMonth = 1

'対象となる月の1日をmyDateとする。
myDate = myYear & "/" & myMonth & "/" & 1

'休日テーブルの変数代入
Set table = ActiveSheet.ListObjects(1)

'休日テーブルからmyDateの日付を探索
table.range.AutoFilter field:=table.ListColumns("日付").Index, Criteria1:=">=" & myDate
table.range.AutoFilter field:=table.ListColumns("休み").Index, Criteria1:="<>〇"

'日付を抽出後のセルの先頭の行を取得
Row = table.DataBodyRange.SpecialCells(xlCellTypeVisible).Row
Clm = table.ListColumns("日付").Index

'第一営業日の取得
myDate = ActiveSheet.Cells(Row, Clm).Value

'第一営業日の曜日を取得
myWeek = Format(myDate, "aaa")

MsgBox ("日付は:" & myDate & vbCrLf & _
        "曜日は:" & myWeek)


End Sub

プログラム的にはちょっと面白みがないですが、
メンテナンスもしやすく、割と実務よりかと思います。

まとめ

いかがでしょうか。

  • 特定の曜日のみ休みのバージョン
  • 特定の曜日+祝日のバージョン
  • カスタマイズバージョン

いろいろなバージョンで作ってみました。

実務的には休日テーブルを作り、
その会社に沿った休日で営業日を算出するのが良いと思われます。