🐕

GASの日直通知で休日をスキップする

に公開

やりたいこと

GoogleSpreadsheet + GAS + Slackで日直管理と通知 では指定した期間ごとに日直を通知していた。
しかし、現実には休日があり、それらの日はスキップしたい。

解:計算した次回通知日が休日の場合は次の候補にする

前回の記事では以下のコードで次回通知日を計算していた。

// work は { "name": "朝会司会", "intervals": 1, "next": '2025-05-23' } のようなオブジェクト
// intervalsは通知間隔日数
// nextは次回通知日のDateオブジェクト
function calculateNextDate(work) {
  const nextDate = work.next
  return new Date(nextDate.setDate(nextDate.getDate() + work.intervals))
}

これを、次回通知日が休日の場合に、さらに intervals を休日にならない日が取得できるまで加算することで実現できる。
休日には2種類あり、「機械的に判断できるもの」と「機械的に判断できないもの」がある。
それぞれについて対方法を考える。

機械的に判断できるもの

「法定休日」と「法定外休日」があり、会社により曜日を指定して運用されていることが多い。
そのため、Dateオブジェクトの曜日でこれらは判定できる。
例えば、土日休みの場合は次のようになる。

const date = new Date()
const isWeekend = date.getDay() === 0 || date.getDay() === 6

機械的に判断できないもの

日本の場合、内閣府により「国民の祝日」が定められている。
これらはの中には日付や曜日で判定するには難しいものがあり、例えば「海の日」は 2025-07-212026-07-20 と年によって違う。
また、会社によっては「創業記念日」や「夏期休暇」、「年末年始休暇」など独自に定義した休日が存在することがある。

これらについては、シートで定義して管理し、コードから呼び出して判定処理に組み込むのが簡単である。
国民の祝日については、 内閣府の 国民の祝日について のページからCSVをダウンロードできる。1955年から全て掲載されているので必要な部分だけ残して、インポートなりコピー&ペーストする。
会社独自の休日については、調べてシートに記載する。

例えば holidays という名前でシートを作成し、以下のような定義を記述する。

date name
2025/1/1 元日
2025/1/13 成人の日
2025/2/11 建国記念の日

判定のためのコードは以下のようになる。

const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('holidays')
const [header, ...rows] = sheet.getDataRange().getValues()
const holidays = rows.map(row => Object.fromEntries(header.map((key, i) => [key, row[i]])))

const date = new Date()
const isHoliday = holidays.some(holiday => holiday.date.getFullYear() === date.getFullYear() && holiday.date.getMonth() === date.getMonth() && holiday.date.getDate() === date.getDate())

休日を判定するコード

上記2点を反映したコードは以下のようになる。

function calculateNextDate(work) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('holidays')
  const [header, ...rows] = sheet.getDataRange().getValues()
  const holidays = rows.map(row => Object.fromEntries(header.map((key, i) => [key, row[i]])))

  let nextDate = work.next
  nextDate = new Date(nextDate.setDate(nextDate.getDate() + work.intervals))

  while (true) {
    if (
      nextDate.getDay() !== 0 && //日曜でない
      nextDate.getDay() !== 6 && //土曜でない
      !holidays.some(holiday => 
        holiday.date.getFullYear() === nextDate.getFullYear() &&
        holiday.date.getMonth() === nextDate.getMonth() &&
        holiday.date.getDate() === nextDate.getDate()
      ) //シートに定義した休日ではない
    ) {
      return nextDate
    }

    nextDate = new Date(nextDate.setDate(nextDate.getDate() + work.intervals))
  }
}

Discussion