[GAS] 日本・アメリカ・台湾で明日が祝日だったらSlackに通知する

## はじめに
[弊社(Whatever Co.)](https://whatever.co/ja/) は、日本(Tokyo)以外にも、US(New York)や台湾(Taipei)にオフィスがあります。
基本的にはそれぞれの国内でチームを組むことが多いですが、案件によっては、日本のメンバーがUSや台湾チームと連携することがあります。

海外チームと連携するにあたり、時差もそうですが、祝日の存在に気をつける必要があります。
各国がいつ祝日なのか？を覚えるのが大変なので、非常にシンプルではありますが、
「明日が祝日だったらSlackに通知する仕組み」を作ってみました。

こんな感じで通知が届きます。
![スクリーンショット 2023-04-05 18.51.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/d54da737-768d-620f-d437-a7a9d2bd3072.png)

（これまではメンバーが手打ちでSlackに投稿してくれていました。大変。。）

## 制作物
下記にコードをアップしています。

[https://gist.github.com/genkitoyama/82d5d7cb9772e403e8e439a634079653](https://gist.github.com/genkitoyama/82d5d7cb9772e403e8e439a634079653)

## やったこと
- 各国の祝日のGoogle Calendarを調べる
- 次の日が平日かつ祝日だったら
- Webhook経由でSlackに通知する
- 毎日実行するようにトリガーを設定する

をやりました。

実装方法はいくつかあると思いますが、手っ取り早いと思ったGASで実装しました。

### 各国の祝日のGoogle Calendarを調べる

日本・アメリカ・台湾に関しては、Googleがすでに祝日用のカレンダーURLを用意してくれているので、それを使用します。

自分は Google Calendar の Add Calendar -> Browse calendars of interest ページに、
 `Regional holidays` の項目があり、そこから `Holidays in Taiwan` や `Holidays in United States` を見つけました。

![スクリーンショット 2023-04-05 18.15.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/f0698af1-6bb9-89ce-4e05-11a8dc3ae467.png)

各カレンダーの詳細を見ると、 `Calendar ID` というものが記載されています。このURLを使用しました。
（余談ですが、最初はChatGPTに質問してたのですが微妙に違うURLが返ってきてたので手動で調べました。）

<img width=500 alt="スクリーンショット_2023-04-05_18_26_53.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/4150e3e1-71ca-5034-ae47-6bd00b4a9dd5.png>

:::note warn
1つハマったこととして、`Holiday calendar content` の設定があります。
これがデフォルトだと `Public holidays and other holidays` となっていますが、このままだと、その国の公的な祝日以外に、ローカルな祝日が含まれてしましました。（そのためオフィスは平日なのに祝日の通知が飛んでしまうことになる）
この項目を `Public holidays only` にすることで、公的な祝日だけを取得することができました。
<img width=500 alt="スクリーンショット_2023-04-05_18_23_10.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/204bba21-9ba2-67f9-1998-6ea27f47899c.png>
:::


### 次の日が祝日かどうかを調べる

GASでカレンダー情報を取得するには、 `CalendarApp.getCalendarById(calendarURL)` を用います。
また、その日にイベント(= 祝日)があるかどうかは、 `getEventsForDay(targetDate)` で判定することができるので、
ここの `targetDate` を、明日（今日のDateに +1 したもの）に設定します。

```js
var today = new Date();
var tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
var events = CalendarApp.getCalendarById(calendarURL).getEventsForDay(tomorrow);
```
これで、次の日が祝日かどうかが判定できます。

### 次の日が平日かつ祝日かどうかを調べる

また、次の日が土日だったら、元々休みで通知する必要がないため、
次の日が月曜〜金曜の平日だった場合のみ、上記処理を行うようにします。

```js
//targetDateが平日だったらtrue、土日ならfalseを返す
function isWorkday(targetDate)
{
  const restOrWork = ["REST","mon","tue","wed","thu","fri","REST"]; // 日〜土
  if ( restOrWork [targetDate.getDay()] == "REST" )
  {
    //console.log("Tomorrow is not a working day.")
    return false;
  }
  return true;
}

//明日が平日の時だけ確認する
if(isWorkday(tomorrow))
{
  ...
}

```

### WebhookでSlackに通知する

通知したい文章を用意したら、SlackのWebhook URLを取得して、叩くだけです。

```js
function postToSlack(payload)
{
  var options = {
    "method" : "POST",
    "payload" : JSON.stringify(payload)
  }

  //slack webhook URL
  const slackURL = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

  var response = UrlFetchApp.fetch(slackURL, options);
}
```

今回の工夫としては、 `payload` に `icon_emoji` や `username` を指定することで、Slack上でわかりやすい見た目なりました。

```js
payload = {
  "text" : remindTexts[0] + countryName + " 🇯🇵" + remindTexts[1] + events, // メッセージの本文
  "icon_emoji" : ":jp:",
  "username" : "Holiday in " + countryName,
  }
```

![スクリーンショット 2023-04-05 19.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/99e55c9c-1bdc-15e8-964e-9a4a88f7a1e2.png)
（台湾に関しては、 `icon_emoji` がSlackに含まれていなかったので、 `icon_url` を使っています。）


### 毎日実行するようにトリガーを設定する

この処理が毎日実行されるようにトリガーを設定します。
今回は正確な時刻に毎回実行する必要はないので、1時間の幅がありますがGAS標準のTriggerを使います。

<img width=500 alt="スクリーンショット 2023-04-05 23.11.11.png" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109722/1ff91304-54fa-bfc9-c8d6-5063404fe8f1.png>

## おわりに

シンプルな仕組みですが、意外と役に立ちそうです。

ちなみに、弊社では [ずっと祝日カレンダー](https://shop.whatever.co/items/69449358) というカレンダーを販売しています！
毎日がどこかの国の祝日になっているカレンダーです。よかったら買ってください。

![](https://baseec-img-mng.akamaized.net/images/item/origin/892c597678361ce73524be17489d66fb.png?imformat=generic&q=90&im=Resize,width=1280,type=normal)

## 参考にした記事
- [GASでGoogleカレンダーの予定を取得する方法！指定期間内のイベントを抽出](https://auto-worker.com/blog/?p=4323)
- [【GAS】休日・祝日を判定する関数](https://qiita.com/jz4o/items/d4e978f9085129155ca6)
- [Googleカレンダーで日本＆海外の祝日を表示する方法（スマホでも）](https://www.iscle.com/web-it/g-drive/g-apps/calendar-shukujitsu.html)
- [GASでSlackのIncoming Webhookを使用して通知する方法](https://specially198.com/how-to-notify-using-slack-incoming-webhook-on-gas/)