[Excel VBA] 年度に関わらず営業日数を算出する方法について紹介
概要
この記事について
About
Excel VBAで営業日数を計算する場合、
自作関数で細かく営業日条件を設定して計算する以外に、
組み込み関数のNetworkDays
を使用する方法がある。
書式:
使用例
使用例としては、通常、次のようになる。
- 祝日(土日以外)のリストをいずれかのシート上に作成する。
- VBAコード上で、上記リストのセル範囲を祝日引数として指定し、営業日数を算出する。
1'******************************************************************************************
2'*機能 :営業日の計算 祝日としてセル範囲使用
3'*引数 :
4'******************************************************************************************
5Public Sub CalcWorkDayUseRange()
6
7 '定数
8 Const FUNC_NAME As String = "CalcWorkDayUseRange"
9
10 '変数
11
12 '営業日:祝日を除く月~金曜日とする
13 'ex.1)2019/12/29から2020/1/6までの営業日を計算する
14 Debug.Print WorksheetFunction.NetworkDays(#12/29/2019#, #1/6/2020#, ThisWorkbook.Worksheets("祝日").Range("B2:B9")) '=3
15 'ex.2)2020/6/14から2020/6/16までの営業日を計算する
16 Debug.Print WorksheetFunction.NetworkDays(#6/14/2020#, #6/16/2020#, ThisWorkbook.Worksheets("祝日").Range("B2:B9")) '=1
17
18 'note)祝日シートには2020年の祝日カレンダーしかないため、
19 ' 他の年の祝日をまたぐ営業日の計算するためには、対象年のカレンダーを追加する必要がある
20 ' ex)2021/6/14から2021/6/16までの営業日を計算すると、6/15(会社設立記念日)が祝日判定されず、3が返る
21 Debug.Print WorksheetFunction.NetworkDays(#6/14/2021#, #6/16/2021#, ThisWorkbook.Worksheets("祝日").Range("B2:B9")) '=3
22
23
24ExitHandler:
25
26 Exit Sub
27
28End Sub
29
課題点
上のコードのハイライトで示されているように、
上記の方法だと、
祝日シートに記述されていない年(2019年以前、2021年以降)の祝日またぎの計算は苦手である。
各年ごとの祝日をシートに準備しなければならないが、
それが作業量とミスの可能性を増やすため、
この記事では年度に関わらず営業日数を算出する方法を紹介したい。
方法
NetworkDays関数の[祝日]引数はセル範囲だけではない
NetworkDays関数の第三引数([祝日])として
セル範囲の他に、配列引数や
Date型の配列変数
をとることができる。
VBAにおいては、
Date型の配列変数
を利用すると 、
年に依らない日数の計算が容易になるかと考えられる。
よって、以下では、
シートに祝日を記述するのではなく、
配列としてVBA上にハードコードすることを基本方針としている。
配列変数取得用のClassを作成
まず、それぞれの祝日を格納している配列変数を取得するClassを作成した。
1'@Folder("Class")
2Option Explicit
3
4'**************************
5'クラス名:ClsSpecialHoliday
6'*祝祭日の設定・取得
7'**************************
8
9'定数欄
10Private Const SOURCE_NAME As String = ""
11
12'変数欄
13Private lArrHoliday() As String '祝祭日(月日のみ)格納先
14
15
16'******************************************************************************************
17'*getter/setter欄
18'******************************************************************************************
19
20'******************************************************************************************
21'*引数 :対象年
22'******************************************************************************************
23Public Property Get arrHoliday(ByVal yy As String) As Date()
24 Dim dateArr() As Date
25 Dim i As Long
26 ReDim dateArr(0 To UBound(lArrHoliday))
27
28 For i = 0 To UBound(lArrHoliday)
29 dateArr(i) = CDate(yy & "/" & lArrHoliday(i))
30 Next i
31 arrHoliday = dateArr
32End Property
33
34
35
36'******************************************************************************************
37'*機能 :Class_Initialize
38'*引数 :
39'******************************************************************************************
40Private Sub Class_Initialize()
41
42 '定数
43 Const FUNC_NAME As String = "Class_Initialize"
44
45 '変数
46
47 '***ここで通年の祝祭日を設定します(○月/○日)***
48 ReDim lArrHoliday(0 To 7)
49 lArrHoliday(0) = "1/1"
50 lArrHoliday(1) = "1/2"
51 lArrHoliday(2) = "1/3"
52 lArrHoliday(3) = "4/29"
53 lArrHoliday(4) = "5/3"
54 lArrHoliday(5) = "5/4"
55 lArrHoliday(6) = "5/5"
56 lArrHoliday(7) = "6/15"
57 '*************************************
58
59
60ExitHandler:
61
62 Exit Sub
63
64
65End Sub
66
67
クラスの利用時は、
インスタンスを生成した後に
配列変数 = object.arrHoliday(string: 対象年)
というように利用する。
もし祝日を追加/削除したければ、
上のコードでハイライトした配列の設定部分を追加したり削除したりすればいい。
営業日の計算
営業日の計算用の関数を書き直すと、
以下のようになる。
1'******************************************************************************************
2'*機能 :営業日の計算 祝日としてハードコードされた値を使用
3'*引数 :
4'******************************************************************************************
5Public Sub CalcWorkDay()
6
7 '定数
8 Const FUNC_NAME As String = "CalcWorkDay"
9
10 '変数
11 Dim objSpecialHoliday As New ClsSpecialHoliday
12
13 '営業日:祝日を除く月~金曜日とする
14 'ex.1)2019/12/29から2020/1/6までの営業日を計算する
15 Debug.Print WorksheetFunction.NetworkDays(#12/29/2019#, #1/6/2020#, objSpecialHoliday.arrHoliday("2020")) '=3
16 'ex.2)2020/6/14から2020/6/16までの営業日を計算する
17 Debug.Print WorksheetFunction.NetworkDays(#6/14/2020#, #6/16/2020#, objSpecialHoliday.arrHoliday("2020")) '=1
18
19 'ex.3)2021/6/14から2021/6/16までの営業日を計算する
20 ' 引数として2021を渡せば2021年の祝日として配列を取得できるため、
21 ' 6/15(会社設立記念日)が祝日判定され、2が返る
22 Debug.Print WorksheetFunction.NetworkDays(#6/14/2021#, #6/16/2021#, objSpecialHoliday.arrHoliday("2021")) '=2
23
24
25ExitHandler:
26
27 Exit Sub
28
29End Sub
30
書き直し前とは異なり、
2021/6/14から2021/6/16までの営業日がかんたんに計算できている。
Furthermore
今回ClsSpecialHolidayクラスにハードコードした祝日配列の内容を
ファイルから取得したりデータベースを利用したりすれば、
さらにメンテナンス性は向上するかと思う。
関連記事
- [Excel VBA] 結合セルにコピーペーストするマクロ
- [Excel VBA] PageSetup.PrintAreaによるシートの印刷範囲の変更を行うときにエラーになる場合&その回避方法
- [VBA] Excelの複数シートをループを使わず一行の処理で非表示・再表示にすることはできる??
- [VBA] ブック内の図形内のテキストを検索・置換するマクロ(Qiitaの記事の拡張)
- [VBA] 関数の引数を変更した場合にコンパイルエラーが多発するのを防ぐテクニック