マクロ VBAで祝休日判定(WBSプログラム➀)
今日は、マクロで祝休日を判定するプログラムを書いていきたいと思います。祝休日処理(今回)+進捗管理処理(次回➁)+ イナズマ線描画(最終回➂)の3回に渡り、書いていきます。
なお、休日判定はWBSほどカッチリしたものでなくても、使えたりしますので、その辺もご紹介します。(ToDo管理等)
なお、基本的なマクロの書き方を知りたい方は、以下の記事を参照ください。
1.休日(土日)の判定の仕方
まずは、土日を判定する方法です。例えば以下のファイルでB列に平日なら「平日」、休日なら「休日」と表示したい場合。
2.コード例
では、コード全体をまず書いて、動かしてみましょう。
こちらからファイルをダウンロードも可能なので、コード書くの面倒な方はダウンロード後に、Alt+F11でVBAを立ち上げ、Module1をクリックしてください。
Sub 土日判定()
Dim targetDay As Date
Dim lastRow, dow As Integer
Dim i As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
targetDay = Cells(i, 1).Value
dow = Weekday(targetDay)
If dow = 7 Or dow = 1 Then
Cells(i, 2).Value = "休日"
Else
Cells(i, 2).Value = "平日"
End If
Next
End Sub
では、コードを”F8”で一行ずつ実行してみましょう。
ローカルウインドウで確認すると、変数には初期値がセットされました。
"F8"を数回押して、Forループに入ると、変数には・・・
値が入っているA列の最終行を確認する、以下のコードで4行目の4を数値(Integer型)が変数lastRowに格納されています。
lastRow = Cells(Rows.count, 1).end(xlUp).Row
また、Forループのための変数iにスタート値である2が数値(Long型)でセットされたのも確認できました。以下の書き方をすると、スタート値である2からlastRow(数値4が格納されている)まで、Nextにたどり着くたびに変数iが1増えて、変数iを3としてまたNextまで処理、また変数iが1増えて、変数iを4として・・・と繰り返し処理がされます。
For i = 2 to lastRow
(処理内容)
Next
では、Nextにたどり着くまでF8で引き続き、実行してみましょう。
4月16日に平日と入りましたね。この時、変数はどのようになっているか、ローカルウインドウで確認してみましょう。
Date型の変数として用意した変数targetDayに、A列2行目の値(4月16日)が格納されているのが分かります。ここの(Cells(i, x))値(.Value)を取得してねというのが以下のコードです。
取得した値をtargetDayに格納しているわけです。
targetDay = Cells(i, 1).Value
3.マクロ(VBA)での曜日取得の仕方
変数dow(day of weekを適当に略しました 笑)には、6という数値が格納されています。曜日を取得しているのは、以下のコードです。
dow = WeekDay(targetDate)
WeekDay(日付型)で、曜日をあらわす数値を取得し、それを変数dowに格納してます。なお、曜日と数値の対比は以下のとおりです。
つまり、6ということは金曜日。平日ですね。
それを以下のIF文で、曜日が1(日曜日)または7(土曜日)ならば(If…Or…Then)、休日。それ以外(Else)ならば平日と判定しています。
If dow = 7 Or dow = 1 Then
Cells(i, 2).Value = "休日"
Else
Cells(i, 2).Value = "平日"
End If
なお、先ほど記載したセルの値を変数に格納した際は、変数 = Cells(x, y).Valueと記載しましたが、Cells(x, y).Value = 変数や値 と記載することでセルにその値を保有させることができます。
では、”F8”でそのまま動かしてみましょう。
無事に、平日・休日を判定して判定結果をB列に表示できました。
4.祝日はどう判定する?
では日付が以下となった場合はどうでしょうか。
とりあえず、さっきのプログラムを動かしてみると。
全部平日になってしまいました。2021年の4月29日は祝日ですよね。
(こちらのサイトからおかりしました)
実は祝日判定はちゃんとやると結構難しいです。ガチなやり方を書いているサイトもあるので、必要な方はそちらを参照ください。
すごいですね。僕は実務で使えればそれいいので、もっと簡易的にやります。数年がかりのプロジェクトもあるとは思いますが、WBSまでの詳細タスクまで落として管理するのは、せいぜい1年分か半年程度じゃないでしょうか。簡単やるにはズバリ・・・祝日一覧があると早いです(笑)
こんな便利なサイトから、祝日一覧を取得しエクセルのシートに追加します。
そして、データをコピーして、祝日一覧など適当なシート名でシート追加し、ファイルにペーストします。(こんな感じ)
5. 休日判定に祝日判定も追加する
祝日判定をまずはModule2として追加します。
調べたい日にちが、祝日一覧に記載されている日付と一致するかをループ処理で確認するプログラムを使っています。
せっかくなので、日付を増やして判定したいと思います。
コード全文は以下の通りです。
Sub 祝休日判定()
Dim lastRow_1, lastRow_2, checkCode As Integer
Dim targetDate As Date
Dim i, j As Long
Dim ws_1, ws_2 As Worksheet
Set ws_1 = Worksheets("Sheet1")
Set ws_2 = Worksheets("祝日一覧")
lastRow_1 = ws_1.Cells(Rows.Count, 1).End(xlUp).Row
lastRow_2 = ws_2.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow_1
targetDate = ws_1.Cells(i, 1).Value
checkCode = 0
For j = 1 To lastRow_2
If targetDate = ws_2.Cells(j, 1).Value Then
checkCode = 1
ws_1.Cells(i, 2).Value = "祝日"
End If
Next
If checkCode = 0 Then
If Weekday(targetDate) = 1 Or Weekday(targetDate) = 7 Then
ws_1.Cells(i, 2).Value = "休日"
Else
ws_1.Cells(i, 2).Value = "平日"
End If
End If
Next
End Sub
むむむ。難しそうですか?美しいコードが書けなくてすいません。
多分、もっと簡潔な美しい記載の仕方はあるんじゃないかと思います。
ただ、そんなに新しい話はないです。新しい書き方・考え方でいうと、大きくは2点です。
※ 先ほど同様にファイルはダウンロードできるようにしておきます。
module2に祝休日判定プログラムがあります。
6.ワークシートオブジェクトを利用する
新しくでてきた話として、まず以下の部分があります。
Dim ws_1, ws_2 As WorkSheet
Set ws_1 = WorkSheets("sheet1")
Set ws_2 = WorkSheets("祝日一覧")
今回は「祝日一覧」シートを参照し、「Sheet1」シートのセルに記載されている日付が祝日の日付と一致するかを確認するプログラムを書いています。
つまり、2シートを跨いで処理をしています。
そんな時は”WorkSheets(シート名あるいはシート番号)” という書き方で、どのシートについて処理したい内容なのかを明記する必要があります。
例えば、Sheet1のA1セルを指定する場合は、以下のとおりです。
WorkSheets("sheet1").Cells(1, 1)
または
WorkSheets(1).Cells(1, 1)
ただ、WorkSheets(シート名)を毎回記載するのは面倒くさいので、Worksheetオブジェクトとして、ws_1と、ws_2を用意しそこにシートを設定(Setを頭につける必要あり)することで、記載を簡潔にしています。
実際はws_2は一回しか使ってないので、今回は不要でしたが・・・笑
7. ループの中のループ、IF文の中のIF文
もう一つ、新しい話としてはループの中にループ、IF文の中にIF文がある部分だと思います。
(1) ループの中のループ
以下の赤➀の中に、黄色➁が存在します。
複雑そうに見えますが、動き方としては、「➁のループ処理全部が、➀のループ処理1回ごとに行われる」となります。
シート1の i行目の1列にある日付を変数targetDateに格納し、➁のループ処理で祝日一覧シートの1行目から最終行目までの1列目にある日付と比較を行い、一致した場合は0を格納しておいた変数checkCodeの値を1に更新します。
➁のループ処理を抜けて、変数checkCodeが0(祝日以外)の場合は、休日判定のプログラムに突入し、変数checkCodeが1(祝日)の場合は、そのまま➀のNextにいって、Sheet1の次の日付を見に行きます。
一つだけ、ForとNextは必ずセットなので、外側の➀と内側の➁、どちらもForとNextが必要です。
(2) IF文の中のIF文
次にIF文の中のIF文を見てましょう。外側にあるIF文➊はcheckCodeが0の場合は、IF文➋の条件式に基づいてプログラムが動きます。
そもそもcheckCodeが1の場合は、その後の処理は行われずNextにたどり着きます。条件式➋内では、曜日が1(日曜日)または、7(土曜日)の場合は、「休日」が、それ以外の場合は「平日」が i 行目の2列に入力されます。
8. プログラム実行
では、プログラムを動かしてみましょう。
”F5”を押して、祝日判定の方のプログラムを動かしてみると・・・
きちんと判定できました。自分でコードを書いて上手くいかなかった方は、よくよくコードを見直してみてください。
F8で1行ずつ実行して、変数の値なども見ていくとどこがおかしいのか、分かったりします。
結構、エラーが出まくって、F8でデバッグしていくその作業自体がとても勉強になったりするので、エラーなんて当たり前くらいの感じで、どんどん自分で書いていきましょう。
次回は、WBSの進捗管理プログラムを説明します。