Power Automate で土日祝祭日や定時を判定する

## 経緯

イベントが発生したら Power Automate から Teams にメンション付きで投稿する時、
土日祝祭日とか定時後とかに投稿したくないじゃないですか？

色々方法はあると思いますが、私がやった方法をメモっておきます

## 前提条件や仕様

* 実際にイベントが発生した日時ではなく、手動フローで日時を生成します
* 便宜上、日時はすべて JST です (実際に Power Automate や Teams では UTC が使われます)
* 祝祭日の情報は配列に入れています
  - SharePoint リストなどにマスタを作る方法もあると思います
* 始業時間(Teams に投稿してよい早朝)は 9 時、終業時間(Teams に投稿したらいけない夕方)は 18 時とします

## フロー全体の説明

まず最初に全体はこのようになっています

![20211231_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/7ea4ebb5-1e19-7036-e568-44ab483b2de2.png)

「手動でフローをトリガーします」と「トリガー時の入力からイベント発生日時用変数(EventDatetime)を生成する」は、実際にイベントが発生したと仮定する日時を生成している前処理となります

次に処理に使う変数を設定していきます

処理では、終業時間を越えているかの確認後、投稿して良い最短の営業日をチェックするループへと入ります

## フローの説明

### 前処理の説明

「手動でフローをトリガーします」については下図のようになっていて、
実際にイベントが発生したと仮定する日時を入力できるようにしています

![20211231_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/d419bd81-6f37-8b39-39ba-954c1c348653.png)


次にトリガーで入力した情報を日付情報にしています
![20211231_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/548812ca-e9f9-b55a-9370-7a7c9f2e1559.png)


値に入っている式は次のようになっています

```bash
concat(triggerBody()['date'], 'T', formatNumber(triggerBody()['number'],'00'), ':00:00')
```

### 処理に使う変数の初期化の説明

「Teams に投稿する日時用変数(TeamsPostDatetime)を初期化する」は単純な初期化です
![20211231_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/b7a87443-b592-04cf-e0e9-093e61158537.png)

「祝祭日用変数(Holiday)を初期化する」は、祝祭日として定義する日付を配列で持ちます
![20211231_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/4aac55f3-d22b-6ccb-d218-e86e6dd37bba.png)

弊社は 12/28 が仕事納めだったので、12/29 から休みにしています

```json
[
  "2021-12-29",
  "2021-12-30",
  "2021-12-31",
  "2022-01-01",
  "2022-01-02",
  "2022-01-03",
  "2022-01-10",
  "2022-02-11",
  "2022-02-23",
  "2022-03-21",
  "2022-04-29",
  "2022-05-03",
  "2022-05-04",
  "2022-05-05",
  "2022-07-18",
  "2022-08-11",
  "2022-09-19",
  "2022-09-23",
  "2022-10-10",
  "2022-11-03",
  "2022-11-23",
  "2022-12-29",
  "2022-12-30",
  "2022-12-31",
  "2023-01-01",
  "2023-01-02",
  "2023-01-03"
]
```

「ループカウント用変数(Count)を初期化する」は単純な初期化です
![20211231_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/e068c646-576e-eb57-4c77-dac73d5394dc.png)


### 「イベント発生時間は 18 時を越えているか」の説明

こちらの処理は下図のようになっています
![20211231_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/234e950f-30e0-9dd1-381a-66d8d6ef25c6.png)

最初の条件式の左辺の式は下記のようになっています

```bash
int(formatDateTime(variables('EventDatetime'),'HH'))
```
つまり、イベント発生日時の時間の部分だけ取得して数値型に変換して、
その時間が 18 時以上かどうかを判定して下記のように変数に値をセットしています
* 18 時を越えていたらループカウントを 1 からスタート
* 18 時より前のときにはループカウントを 0 からスタート

このあとの処理でループカウント分日付を進めて、営業日かどうかを判定していくので、
18 時を越えたら 1 からスタートさせているということは、
イベント発生日の翌日から判定をスタートさせていくということになります


### 「営業日確認ループ」の説明

営業日確認ループでは、 `do until` を使ってループを回しています
![20211231_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/766a9e70-db8c-2c0b-74f7-20fe5fc0af8f.png)

条件式の左辺の式は下記のようになっています

```bash
empty(variables('TeamsPostDatetime'))
```

つまり、変数「TeamsPostDatetime」に値が入ったらループを抜けるようにしています

ついでに、念の為、ループの制限回数を 60 回から 14 回にしています

続いて、「イベント発生日にループカウント分の日を加算した日が土日祝祭日ではない」は下図のようになっています
![20211231_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/95ae32f4-8112-fa26-f432-f2beefcbcda8.png)

条件文の最初と 2 番目の左辺の式は下記のようになっています

```bash
dayOfWeek(addDays(variables('EventDatetime'), variables('Count')))
```
イベントが発生した日付にループカウント分の日数を足した日付の曜日を求めています
こちらは日曜日を 0 、土曜日を 6 として返ってきます

条件文の最後の左辺の式は下記のようになっています

```bash
contains(variables('Holiday'), formatDateTime(addDays(variables('EventDatetime'), variables('Count')), 'yyyy-MM-dd'))
```
イベントが発生した日付にループカウント分の日数を足した日付が、祝祭日用変数(Holiday)の
値に一致するのがあるか確認しています(あれば true が返ってきます)

つまりこちらの条件文では、「イベントが発生した日付にループカウント分の日数を足した
日付が、日曜日か土曜日ではなく、祝祭日でもないとき」となり、その条件を満たしたときに、
「Teams に投稿する日時用変数(TeamsPostDatetime)」に下記式で値をセットしています
```bash
formatDateTime(addDays(variables('EventDatetime'), variables('Count')), 'yyyy-MM-ddT09:00:00')
```

ループの最後にカウント用変数を +1 カウントアップしています
![20211231_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/c5fbd698-e413-3e89-a590-9595074f922a.png)

## 実際に動かしてみる

### イベント発生日時が 2021/12/27 08:00:00 の時
イベント発生日が営業日で、予定通り 2021/12/27 09:00:00 となっている
![20211231_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/d35847df-2022-9831-ffb1-37c889c6c189.png)

### イベント発生日時が 2021/12/27 18:00:00 の時
イベント発生日は営業日だが定時外、翌日は営業日なので 2021/12/28 09:00:00 となっている
![20211231_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/b7c5de50-2f94-729d-5224-9ec692ce6627.png)

### イベント発生日時が 2021/12/28 18:00:00 の時
イベント発生日は営業日だが定時外、翌日から年明け 3 日まで祝祭日登録されているので、
2022/01/04 09:00:00 となっている
![20211231_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118961/98a3cad6-fde2-786d-d6d4-f11afced223e.png)