PowerShellで次回営業日判定

##【作成の趣旨や前提条件など】
PowerShellで次回営業日はいつなのかを判定するスクリプトを作成してみました。

Trelloと連携して次回営業日期限のタスクをSlackかChatworkへ飛ばすスクリプトを組んでみたいと考えており、その一部分をとりあえず共有します。

所属企業によって休日の概念はマチマチだと思うので今回は以下の前提条件で作成しています。

###◆前提条件
　　・実行日から数えた次回営業日とする。
　　・土日祝日は休みとする。
　　・その他、企業ごとの特別休暇も追加で判定可能とする(「基本情報の設定」の項にて後述)
　　・関数化はしない(したい方は編集すればできるので個別にやってください)

土日祝日に出勤される方は泣いてください。

本記事ではコードだけ「こんな感じで組めました」というのを記載していきますのであらかじめご了承ください。「もっといい方法あるよ！」、「こういう組み方もあるよ！」などありましたらぜひコメントください。

##【スクリプトの仕様説明】
###◆スクリプトの全体構成
スクリプト全体は以下の通りです。

```POWERSHELL:TaskSend.ps1

##################
# 次回営業日判定 #
##################

#基本情報の設定
$NEXTDATE = (Get-Date).AddDays(1) #本日か+1の日付を入れる
$HOLIDAYFILE = Get-Content C:\Tools\TaskSend\\holidaylist.txt #祝日(厳密には会社の土日以外の定休日)をリスト化したファイル
$HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
$WEEKDATE = ($NEXTDATE).DayOfWeek


###次回営業日になるまで永久ループ
do {
    do {
        #土日判定
        if ( $WEEKDATE -eq "Saturday" ) {
            $NEXTDATE = $NEXTDATE.AddDays(2) #土曜日に+2日して月曜日に合わせる
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
     } elseif ( $WEEKDATE -eq "Sunday" ) {
            $NEXTDATE = $NEXTDATE.AddDays(1) #日曜日に+1日して月曜日に合わせる
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
     }
        #祝日判定
        $HOLIDAYFILE | `
        foreach -Process { if ( $HOLIDATE -eq ( $_ )) {
            $NEXTDATE = $NEXTDATE.AddDays(1) #祝日に+1日して翌日で再度ループ判定
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
            } 
         } `
    } while ( $WEEKDATE -eq "Sunday")
} while ( $WEEKDATE -eq "Saturday")

"次回営業日は" + $NEXTDATE.ToString('MM/dd(ddd)') + "です。"
```

最終的に```$NEXTDATE```を整形した日付が次回営業日として一行で出力されるようになっています。本日(2018/04/30)に実行した場合は以下の通りの結果になります。

```POWERSHELL:2018/04/30に実行した場合
次回営業日は05/01(火)です。
```

全体の処理分岐としては、```$NEXTDATE```に本日日付+1の日付を格納し、以下の順番でループしていき、全ての条件に合致しなくなった日付を結果として出力するようにしています。

　①土曜日かどうか判定(土曜日であれば```$NEXTDATE```に+2する)
　②日曜日かどうか判定(日曜日であれば```$NEXTDATE```に+1する)
　③祝日(企業での特別休暇含む)かどうか判定(祝日であれば```$NEXTDATE```に+1する)
　④項番①～③までの処理後に日曜日かどうか判定し、日曜日ならもう一度①～③の処理を実施
　⑤項番①～④までの処理後に土曜日かどうか判定し、土曜日ならもう一度①～④の処理を実施
　⑥項番⑤で合致しない場合、「次回営業日は〇月〇日(曜日)です。」と出力

図解などを描けばいいのですが、、めんどくさいです。すみません。

なおスクリプト冒頭の```$NEXTDATE = (Get-Date).AddDays(1)```の```AddDays(n)```のnの値を任意に変えれば日付をずらして判定することもできます。試しにいくつかの結果を以下に載せておきます。

```POWERSHELL:AddDays(2)---2018/05/01実行基準の場合
次回営業日は05/02(水)です。
```
```POWERSHELL:AddDays(3)---2018/05/02実行基準の場合
次回営業日は05/07(月)です。
```
```POWERSHELL:AddDays(12)---2018/05/11実行基準の場合
次回営業日は05/14(月)です。
```

##【スクリプト内部の詳細説明】
ではコメントのブロックごとに詳細説明していきます。

###◆基本情報の設定

```POWERSHELL:基本情報の設定
$NEXTDATE = (Get-Date).AddDays(1) #本日か+1の日付を入れる
$HOLIDAYFILE = Get-Content C:\Tools\TaskSend\\holidaylist.txt #祝日(厳密には会社の土日以外の定休日)をリスト化したファイル
$HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
$WEEKDATE = ($NEXTDATE).DayOfWeek
```
```(Get-Date).AddDays(n)``` で本日の日付に任意の日数分を増減することができます。例えばnを3とすれば3日分先の日付を取得し、-3であれば3日分過去の日付を取得します。

```holidaylist.txt``` はネット上の日本の祝日が掲載されているサイトからデータを参照してリスト化したファイルです。記載内容は以下の通りです。

```:holidaylist.txt
2018-01-01
2018-01-08
2018-02-11
2018-02-12
2018-03-21
....(省略)...
2020-12-23
```
私はとりあえず2020年分まで入れました。形式は```yyyy-MM-dd```で出していますので、EXCELで整形してからテキストファイルへ貼ると楽ちんです。

なお祝日以外で企業のローカルルールで特別休暇になる日付がある場合、このリストに追記するだけで勝手に判定してくれます。その際必ず日付昇順で追記してください。ちゃんと判定してくれなくなる可能性があります。

```($NEXTDATE).ToString("yyyy-MM-dd")```で ```$NEXTDATE``` をToStringメソッドで```yyyy-MM-dd```形式に整形しています。後ほど祝日判定時に利用します。

```($NEXTDATE).DayOfWeek``` で```$NEXTDATE``` の曜日が出力されます。出力例は以下の通りです。

```POWERSHELL:DayOfWeekメソッドの出力例
PS C:\Users\TASK-PC> (Get-Date).DayOfWeek
Monday
```
あとで土曜日と日曜日判定に利用します。

###◆次回営業日になるまで永久ループ
処理ごとに説明します。

####①と②：土日判定
```POWERSHELL:土日判定
        if ( $WEEKDATE -eq "Saturday" ) {
            $NEXTDATE = $NEXTDATE.AddDays(2) #土曜日に+2日して月曜日に合わせる
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
      } elseif ( $WEEKDATE -eq "Sunday" ) {
            $NEXTDATE = $NEXTDATE.AddDays(1) #日曜日に+1日して月曜日に合わせる
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
      }
```
if文で```$WEEKDATE```が土曜日(=Saturday)であれば、各種DATE変数に+2日した日付を入れるようにしています。意図的に月曜日(=祝日でなければ次回営業日と考える)にするためです。

同様の理由で日曜日(=Sunday)であれば、＋1日にするようにしています。

####③：祝日判定
```POWERSHELL:祝日判定
        $HOLIDAYFILE | `
        foreach -Process { if ( $HOLIDATE -eq ( $_ )) {
            $NEXTDATE = $NEXTDATE.AddDays(1) #祝日に+1日して翌日で再度ループ判定
            $HOLIDATE = ($NEXTDATE).ToString("yyyy-MM-dd")
            $WEEKDATE = ($NEXTDATE).DayOfWeek
            } 
         } `
```
```$HOLIDAYFILE``` にリスト化した日付を一行ずつ読み取るためにパイプでforeachコマンドレットに渡しています。foreachは渡されたデータを読み込み、```-Process```で定義したスクリプトブロック{ }内の処理に準じてループ処理してくれます。なお```-Process``` は省略可能です。

```-Process``` 内のif文は```$HOLIDATE``` を```( $_ )``` と等しいかどうか判定し、等しければ各DATE変数を+1(=翌日にずらす)しています。翌日にずらしたあと再度リストファイルを読み込んで次の祝日との判定を繰り返すようになっています。

####④と⑤：土日でなけれ永久ループ
```PowerShell:土日でなけれ永久ループ
do {
    do {
        #土日判定
       ................
       ................
       ................
        #祝日判定
       ................
       ................
       ................
   
    } while ( $WEEKDATE -eq "Sunday")
} while ( $WEEKDATE -eq "Saturday")
```
```do~while``` で条件に合致しない限りは土日判定と祝日判定の処理を永久にループ処理させるようにしています。```do~while```を二回続けるのがカッコ悪いのでなにか良い方法ないですかなと探しましたがありませんでした。あれば教えてください...!!!!

####⑥：出力結果の表示
```PowerShell:出力結果の表示
"次回営業日は" + $NEXTDATE.ToString('MM/dd(ddd)') + "です。"
```
最後にループを抜け出した```$NEXTDATE```をToStringで整形して文章にして完成です。


##【感想】
サクッと作れました。PowerShellのいいところは選択肢の幅な気がします。慣れてくれば選択肢がいくつも浮かぶので、結構簡単に組めるようになります。

今度はTrelloAPIで取得したデータを整形してEXCELに出力するところをやってみたいです。


ここまでお読み頂きありがとうございました。
なにかありましたらコメント頂ければありがたいです。