GASで休日かどうかを判定する方法

Slackで定期的なリマインドをするようなとき、日本の祝日や会社の休日を考慮してくれないの、モヤっとしません？
そんなとき、今日がお休みなのかどうかとか、明日から何日お休みなのかとかをチェックできる関数をGASで用意しておくと便利です。
ということで、土日祝に加えて会社の休日も含めて休みかどうか判定するためのGASを書いてみました。

# プログラム
```javascript
/**
 * 該当年の会社指定の休日リストを作成して返却する
 *
 * @param year 作成する休日リストの年（2020を指定すると2020年の休日リストを返却する）
 * @return Date型のリストで会社指定の休日リストを返却する
 */
function getDayOffList(year) {
  // 会社指定の休日リスト（年末年始や夏季休暇などの日付を入れる）
  const DAY_OFF_LIST = ['/01/02', '/01/03', '/12/30', '/12/31'];
  return DAY_OFF_LIST.map( function(dayOff) {
    return new Date(year + dayOff);
  })
}

/**
 * 会社が休みかどうか判定
 * 
 * @param targetDate 判定する日付
 * @param dayOffList 会社指定の休日リスト（getDayOffListで作成したリスト）
 * @return 会社が休みのときtrue
 */
function isDayOff(targetDate, dayOffList) {
  const isWeekendOrHolidayTarget = isWeekendOrHoliday(targetDate);
  const isDayOff = dayOffList.includes(targetDate);
  return isWeekendOrHolidayTarget || isDayOff;
}

/**
 * 祝日または土日かどうかを判定して返却する
 * 
 * @param targetDate 判定する日付
 * @return 祝日または土日のときtrue
 */
function isWeekendOrHoliday(targetDate) {
  const isWeekendTarget = isWeekend(targetDate);
  const isHolidayTarget = isHoliday(targetDate);
  return isWeekendTarget || isHolidayTarget;
}

/**
 * 土日かどうかを判定して返却する
 * @param date 判定する日付
 * @return 土日のときtrue
 */
function isWeekend(date) {
  const day = date.getDay();
  return (day === 6) || (day === 0);
}

/**
 * 祝日かどうかを判定して返却する
 * 
 * @param targetDate 判定する日付
 * @return 祝日のときtrue
 */
function isHoliday(targetDate) {
  const CALENDAR_ID = "ja.japanese#holiday@group.v.calendar.google.com";
  const holidayCalendar = CalendarApp.getCalendarById(CALENDAR_ID);
  const holidayEvents = holidayCalendar.getEventsForDay(targetDate);
  return holidayEvents.length > 0;
}
```

# 解説
読むと大体わかると思いますが、「土日かどうか」「祝日かどうか」「会社指定の休日かどうか」をそれぞれ判定して、orで繋げているだけです。

## 土日かどうか
```javascript
/**
 * 土日かどうかを判定して返却する
 * @param date 判定する日付
 * @return 土日のときtrue
 */
function isWeekend(date) {
  const day = date.getDay();
  return (day === 6) || (day === 0);
}
```
DateオブジェクトのgetDay()関数を呼び出すと曜日が取得できるので、土日を表す0、6のいずれかであればtrueを返すようになっています。

## 祝日かどうか
```javascript
/**
 * 祝日かどうかを判定して返却する
 * 
 * @param targetDate 判定する日付
 * @return 祝日のときtrue
 */
function isHoliday(targetDate) {
  const CALENDAR_ID = "ja.japanese#holiday@group.v.calendar.google.com";
  const holidayCalendar = CalendarApp.getCalendarById(CALENDAR_ID);
  const holidayEvents = holidayCalendar.getEventsForDay(targetDate);
  return holidayEvents.length > 0;
}
```
日本の祝日はGoogleカレンダー側が用意してくれています。該当のカレンダーIDを使ってカレンダーを取得し、該当日にイベントがあるかないかで祝日かどうかを判定できます。

## 会社が休みかどうか
```javascript
/**
 * 該当年の会社指定の休日リストを作成して返却する
 *
 * @param year 作成する休日リストの年（2020を指定すると2020年の休日リストを返却する）
 * @return Date型のリストで会社指定の休日リストを返却する
 */
function getDayOffList(year) {
  // 会社指定の休日リスト（年末年始や夏季休暇などの日付を入れる）
  const DAY_OFF_LIST = ['/01/02', '/01/03', '/12/30', '/12/31'];
  return DAY_OFF_LIST.map( function(dayOff) {
    return new Date(year + dayOff);
  })
}

/**
 * 会社が休みかどうか判定
 * 
 * @param targetDate 判定する日付
 * @param dayOffList 会社指定の休日リスト（getDayOffListで作成したリスト）
 * @return 会社が休みのときtrue
 */
function isDayOff(targetDate, dayOffList) {
  const isWeekendOrHolidayTarget = isWeekendOrHoliday(targetDate);
  const isDayOff = dayOffList.includes(targetDate);
  return isWeekendOrHolidayTarget || isDayOff;
}
```
getDayOffListを使うと、日付文字列の配列から、指定した年の会社指定の休日配列が取得できます。
この配列に日付が含まれているかどうかを判定することで、会社指定の休日かどうかを判定できます。
ここで注意事項としては、翌日が休みかどうかを判定したい場合は、会社の休日リストを今年だけでなく来年分も作成して繋げてからisDayOff関数に入れる必要があります（年末年始対応のため）。

# その他
自分は複数の日付で判定処理を一度に行うようなGASプロジェクトがあったので、実はカレンダーアクセスの回数を減らすため祝日リストは外から入れられるようにしたりしていますが、普通に使う分にはこの状態でも使えると思います。
翌日がおやすみかどうか判定できると、明日から何連休だよ！とslack通知したりできて便利です。