見出し画像

マクロ VBAで祝休日判定(WBSプログラム➀)

今日は、マクロで祝休日を判定するプログラムを書いていきたいと思います。祝休日処理(今回)+進捗管理処理(次回➁)+ イナズマ線描画(最終回➂)の3回に渡り、書いていきます。

なお、休日判定はWBSほどカッチリしたものでなくても、使えたりしますので、その辺もご紹介します。(ToDo管理等)
なお、基本的なマクロの書き方を知りたい方は、以下の記事を参照ください。

1.休日(土日)の判定の仕方

まずは、土日を判定する方法です。例えば以下のファイルでB列に平日なら「平日」、休日なら「休日」と表示したい場合。

画像1

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”で一行ずつ実行してみましょう。

画像2

ローカルウインドウで確認すると、変数には初期値がセットされました。

画像3

"F8"を数回押して、Forループに入ると、変数には・・・

画像4

画像5

値が入っている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で引き続き、実行してみましょう。

画像6

4月16日に平日と入りましたね。この時、変数はどのようになっているか、ローカルウインドウで確認してみましょう。

画像7

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ということは金曜日。平日ですね。

画像8

それを以下の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”でそのまま動かしてみましょう。

画像9

無事に、平日・休日を判定して判定結果をB列に表示できました。

4.祝日はどう判定する?

では日付が以下となった場合はどうでしょうか。

画像10

とりあえず、さっきのプログラムを動かしてみると。

画像11

全部平日になってしまいました。2021年の4月29日は祝日ですよね。

画像12

(こちらのサイトからおかりしました)

実は祝日判定はちゃんとやると結構難しいです。ガチなやり方を書いているサイトもあるので、必要な方はそちらを参照ください。

すごいですね。僕は実務で使えればそれいいので、もっと簡易的にやります。数年がかりのプロジェクトもあるとは思いますが、WBSまでの詳細タスクまで落として管理するのは、せいぜい1年分か半年程度じゃないでしょうか。簡単やるにはズバリ・・・祝日一覧があると早いです(笑)

こんな便利なサイトから、祝日一覧を取得しエクセルのシートに追加します。

​そして、データをコピーして、祝日一覧など適当なシート名でシート追加し、ファイルにペーストします。(こんな感じ)

画像13

5. 休日判定に祝日判定も追加する

祝日判定をまずはModule2として追加します。
調べたい日にちが、祝日一覧に記載されている日付と一致するかをループ処理で確認するプログラムを使っています。

せっかくなので、日付を増やして判定したいと思います。

画像14

コード全文は以下の通りです。

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回ごとに行われる」となります。

画像15

シート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列に入力されます。

画像16

8. プログラム実行

では、プログラムを動かしてみましょう。
”F5”を押して、祝日判定の方のプログラムを動かしてみると・・・

画像17

きちんと判定できました。自分でコードを書いて上手くいかなかった方は、よくよくコードを見直してみてください。
F8で1行ずつ実行して、変数の値なども見ていくとどこがおかしいのか、分かったりします。
結構、エラーが出まくって、F8でデバッグしていくその作業自体がとても勉強になったりするので、エラーなんて当たり前くらいの感じで、どんどん自分で書いていきましょう。

次回は、WBSの進捗管理プログラムを説明します。


この記事が気に入ったらサポートをしてみませんか?