Power Automate：Googleカレンダーでイベント追加・更新・削除→Outlookカレンダーでイベント追加・更新・削除　「終日」対応



## 目標

追加，更新，削除のそれぞれについて目標を定める．

### イベントの追加
Googleカレンダーでイベントが追加されたらOutlookカレンダーにイベントを追加する．

反映させたい項目は以下の3つ．
-  タイトル
-  開始時刻
-  終了時刻

またGoogleカレンダーで「終日」のイベントとした場合は，
Outlookカレンダーでも「終日」のイベントにする．

### イベントの更新
Googleカレンダーのイベントが更新されたらOutlookカレンダーの該当イベントを更新する．

反映させたい項目は追加の時と同様に以下の3つ．
-  タイトル
-  開始時刻
-  終了時刻

またGoogleカレンダーで「終日」のイベントにした場合は，
Outlookカレンダーでも「終日」のイベントにする．

### イベントの削除
Googleカレンダーのイベントが削除されたらOutlookカレンダーの該当イベントを削除します．

## 実装
定めた目標を達成できるようにPowerAutomateを実装する．

### トリガー
Googleカレンダーの
「カレンダーでイベントが追加、更新、削除されたとき」
トリガーを使用する．

Googleにログイン後，カレンダーIDでトリガー元となる予定表を選択する．
繰り返し発生するイベントに関してはいじらない．（繰り返しにした場合最初のイベントのみがOutlookカレンダーに反映されます．）
![PA_GCal_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/63f8dbcf-c0ab-0723-b114-d7158c56dba8.png)

### 分岐
イベントの追加・更新・削除に応じて場合分けを行う．

イベントの更新・削除の場合には該当のイベントをOutlookカレンダーから取得しなければなりません．
そこで，まず初めに追加された場合のみを分岐します．

「条件」アクションで，「アクションの種類」が「added」と等しいかどうかを判定します．
[2022.10.14更新]：createdになることもあるようなので，「または」で条件を追加しました．
![PA_GCal_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/c3cfd363-00c9-1f33-4cfc-e11b0d68618b.png)

すると，「はい」の方にはイベントが追加されたときのアクションを，「いいえ」の方にはそれ以外の場合のアクションを用意すればよくなります．

### 追加
３つのアクションのうち「追加」を分離できたので，そちらのアクションを完成させてしまいます．

Outlookカレンダーの「イベントを作成する (V3)」アクションを使用し，必要項目を指定していけば簡単にできそうですが，
ここに「終日」の罠があります

Googleカレンダーで開始時刻と終了時刻を設定した場合はタイムゾーンを設定せずとも正しくOutlookに反映されます．
しかし，「終日」のイベントに設定すると当日の9時から翌日の9時の予定となってしまいます．
日本標準時が世界標準時より9時間早いため補正されてしまうのだと思われます．

それならば，と「終日」イベントに対応するために「イベントを作成する (V3)」アクションでタイムゾーンを日本標準時に合わせると，
今度は開始時刻と終了時刻を設定した予定の場合にくるってしまいます．

よって，開始時刻が設定されているイベントなのか，「終日」のイベントなのかによってアクションを分岐させる必要があります．

開始時刻を設定した場合は次のような値がわたります．
例：開始時刻を2021年12月10日午前11時00分とした場合
`2021-12-10T02:00:00+00:00`

一方「終日」のイベントに設定した場合は次のような値がわたります．
例：2021年12月10日の終日イベントとした場合
`2021-12-10`

（この様子はフローのテストをすることにより確認することもできます．）

したがって，開始時刻としてわたってきた値に"T"が含まれているかどうかで分岐をすることができます．

次の分岐を用意し，「はい」の方には時刻設定をした場合のアクションを，「いいえ」の方には終日設定した場合のアクションを用意します．
![PA_GCal_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/a89f1224-da73-5794-2e5d-7fd7630f2219.png)

「はい」の方のアクションをまず考えます．
Outlookカレンダーの「イベントを作成する (V3)」アクションを使用し，必要項目を指定します．
今回反映させたい情報はタイトル，開始時刻，終了時刻だったので，下図のようになります．
![PA_GCal_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/d223c91b-a448-1272-4bcc-6fce78447be1.png)

開始時刻としてわたってきた値が世界標準時になっているので，タイムゾーンは世界標準時としておきます．
本文にイベントIDを入れていますが，これは後々必要になります．

「いいえ」の場合も同じアクションを用意し，タイムゾーンは日本標準時に設定します．

以上でGoogleカレンダーでイベントが追加されたときのアクションは完成です．

フローは下図のようになっているはずです．
![PA_GCal_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/f7a4e0d8-e829-ff0e-a36d-010179f99739.png)

### 該当イベントの取得
次に更新・削除が行われた場合のアクションを作成していきます．
（最初の分岐で「いいえ」に来た際のアクションです．）

更新・削除を行う場合はOutlookから該当のイベントを取得する必要があります．
更新であるか削除であるかに関わらず行う処理は同じなので，まずは該当イベントを取得するアクションを作成します．

まずはOutlookカレンダーに登録されているすべてのイベントを取得します．
今回繰り返しイベントの処理を行わないことにしているので，イベントの数は有限個に収まります．

Outlookの「イベントを取得する(V3)」アクションを使用します．
予定表IDだけ指定すれば十分です．

[2022.10.14追記]
イベントは上限256個が取得されます．
デフォルトでは，古いものから256個取得されます．
したがって，累計イベント数が256を超えると欲しい威厳とが取得できない可能性があります．
詳細オプションの「並び替え順」フィールドで，`start/dateTime desc`を設定しましょう．

![PA_GCal_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/6dabdd9f-4c21-1ab2-792d-e551d8d6ffa3.png)

次に該当のイベントのみ取り出します．
「アレイのフィルター処理」アクションを使用して，該当のイベント一つを取り出します．

ここで注意が必要です．
タイトルや開始時刻が一致するものでフィルターしたとしても，複数検索出来てしまう可能性があります．
ここでイベントのIDが役に立ちます．

Googleカレンダーではそれぞれのイベントに異なるイベントIDが与えられています．
Outlookカレンダーでも同様にIDが存在します．
しかしながら．GoogleカレンダーとOutlookカレンダーのIDは同じではありません．
したがって，更新や削除が行われたGoogleカレンダーのイベントIDと，それに該当するOutlookカレンダーのイベントIDは異なります．
そのため，GoogleカレンダーのイベントIDをOutlookカレンダーのイベントのどこかに覚えさせる必要があります．
今回Outlookカレンダーにイベントの本文を反映させないため，その枠にGoogle化カレンダーのイベントIDを格納すればよいわけです．

フィルター処理では，イベントの本文にGoogleカレンダーのイベントIDが含まれているかどうかを判定します．
「等しい」ではなく「含まれる」で判定するのには理由があります．

Outlookカレンダーではイベントの本文をHTML形式で格納しています．
したがって，イベントIDがXXXXだった場合，イベントの本文として得られる値は次のものになります．
`<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n</head>\r\n<body>\r\n<p>XXXX</p>\r\n</body>\r\n</html>\r\n`
「含まれる」でフィルターした方がよさそうですね．

さて，フィルターアクションは下図のようになります．
![PA_GCal_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/117e5c1c-14ad-6d97-4959-6bec940abf8f.png)

以上により該当イベントを取得することができました．
これまでのアクションをまとめると下図の用になっているはずです．
![PA_GCal_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/cb30deeb-6e01-ad14-1e03-9399aa0714a6.png)

### 更新・削除の分岐
更新・削除が行われた際のアクションのうち，共通のアクションは作成しました．
よって，次に更新が行われた場合と削除が行われた場合を分ける分岐が必要です．
最初の分岐とほとんど同じです．
![PA_GCal_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/b9ee70d0-6464-dc5c-ae30-dfbf86624734.png)
削除が行われた場合は「はい」，更新が行われた場合は「いいえ」に入ります．

### 削除
削除が行われた場合のアクションを作成します．
Outlookカレンダーから該当のイベントを削除したいです．
よって，Outlookの「イベントの削除」アクションを使用します．
予定表IDとイベントIDを指定します．
ここでのイベントIDとは，Outlookカレンダーのイベントに与えられているIDです．
よって，先ほど取得したOutlookカレンダーのイベントのIDを指定します．
イベントのIDを指定すると，「イベントの削除」アクションを覆うように「Apply to each」アクションが追加されます．
一般にフィルタによって取得されるイベント等は複数であるため，その一つ一つについてアクションを適応するためのものです．
今回はIDを利用することでフィルタで取得されるイベントは一つになっていますが，Apply to eachがあっても問題はありません．
アクションは下図のようになります．
![PA_GCal_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/85f08428-8faa-87a2-951f-967a9deee0e7.png)

### 更新
更新が行われた場合のアクションを作成します．
Outlookカレンダーの該当イベントの内容を更新したいです．
よって，Outlookの「イベントを更新する(V3)」アクションを使用します．
追加が行われた場合のアクションと同じように記述します．
唯一，IDを記入するところには，削除の場合と同じようにフィルターを通ってきたイベントのIDを入れます．
これにより，削除の時と同様，「Apply to each」アクションが追加されますが，気にしないでください．
更新部分のアクションは下図のようになります．
![PA_GCal_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/205e03d3-be1d-308c-186d-a076eeead7b0.png)


更新の際も時刻設定されているか終日設定されているかによって場合分けが必要です．
追加アクションと同じように分岐を用います．

## 完成
以上をすべて行うと，下図のようになります．
これで完成です．
Googleカレンダーでアクションを起こしてからフロー実行されるまで数分かかる場合はありますが，
購読機能を利用するよりは断然早いです．
![PA_GCal_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280154/dc59510a-a691-7644-386c-840a5100f53b.png)