MENU

【GAS】毎年自動更新される祝日リスト (Google スプレッドシート) を作ってみよう!

  • URLをコピーしました!
gas-holidays_featured image

こんにちは! くのーるです!

この記事では、Google Apps Script (GAS) をつかった「Google スプレッドシート上で毎年自動更新される 最新の祝日リスト」をつくるレシピをご紹介いたします。

それではレッツゴー! 🚀

目次

祝日リストを作る意味

まずはじめに Google スプレッドシートで作る祝日リストとは……

こちらです! (どん!)

祝日以外にも会社指定の休業日 (夏季・冬季休暇) もセットしています

こちら一見、祝日情報をただリスト化しただけのものではあるんですが、スプレッドシートで予定管理表などを作ることがある場合、最新の祝日リストを作っておくことはマスト といっても過言ではありません。

祝日リストは汎用性が高く、このような最新のマスターシートを 1 枚用意しておけば、他のシートから参照して祝日判定に使えるすぐれものです。

具体的には Google スプレッドシートで作られた予定管理表があるとして、祝日に該当する行を色付け したり、WORKDAY 関数の引数として利用 するなど、さまざまなシーンで祝日リストは使われます。

さて本題に入る前に、祝日リストを作っておくと便利な活用例をいくつか見てみましょう!

祝日リストの活用例: 祝日に該当する行の色付け

Google スプレッドシートでは、条件付き書式 のカスタム数式機能を使用することで、祝日の行のみを色付けすることができます。

たとえば、さきにご紹介した祝日リストのシートを含むスプレッドシートがあるとして、条件付き書式より以下のカスタム数式を設定します。

=COUNTIF(INDIRECT("祝日!$B$2:$B$29"),$A1)=1

すると以下のように、祝日リストで定義している日付部分に色がついたことがわかります。

予定管理表などでよく見かける処理ですね。

gas-holidays_003

祝日リストの活用例: WORKDAY 関数の引数

つぎに WORKDAY 関数の引数として活用する例を見てみましょう。

WORKDAY 関数とは、土日・祝日を除外して期日を求める場合に使われる関数で、祝日リストの用意が必須となっています。

たとえば予定管理表において「2022/02/08 (火) の 3 日後の営業日」をセットしたいケースがあるとして、以下の関数をセルに仕込んでおきます。

=WORKDAY("2022/02/08", 3, 祝日データ)

このとき 2022/02/08 の 3 日後にあたる日付は、建国記念日である 2022/02/11 (金) にあたります。祝日リストの定義上、この日付は営業日から除外されます。

くわえて WORKDAY 関数は自動的に土日を除外するため、結果として 2022/02/14 (月) が 3 営業日後の日付として正しく求められます。

gas-holidays_002
WORKDAY 関数による祝日除外の例

ほんの一例ではありますが、祝日リストを作る理由、利便性について知っていただけたかと思います。

祝日リストは絶対 GAS で作ったほうがいい!

さて、ここまでは祝日リストのシートを参照した活用例をみていただきましたが、一つだけ注意点があります。

それは、祝日リストの更新作業 (メンテナンス) です。

当然ながら 祝日情報は毎年更新が必要 であり、リストが最新の状態でないと判定用データとして使い物になりません。

そのため通常は年末などに、翌年一年分の祝日情報をセットするといったメンテナンスが求められます。

かんたんな更新作業ではありますが、これを忘れてしまうと一大事です!

そこでこの記事では GAS をつかい、更新作業を自動化するスクリプト を作成していきたいと思います。

GAS コーディング

設計

ざっくりと以下のような設計で GAS コーディングをおこないたいと思います。

STEP
Google カレンダー「日本の祝日」情報の取得

Google カレンダーには標準で「日本の祝日」カレンダーが公開されています (ありがたやー!)。

祝日リストの作成時には、本カレンダー情報を利用したいと思います。

会社指定の休業日 (夏季・冬季休暇) については、別途コード内で定義することとします。

現在 Google カレンダー「日本の祝日」は、今年を基準として、前年の 01 月 01 日から再来年の 01 月 01 日まで の祝日情報が登録されている仕様となっています。今回紹介するコードについては問題ありませんが、取得可能な期間が決まっていることは留意してください。

STEP
シートの更新

Google カレンダーで取得した「日本の祝日」情報をもとにシートの更新をおこないます。

Google スプレッドシートには、 あらかじめ祝日情報の貼り付け先となる以下の「祝日」シートを作成しておきます。

gas-holidays_006
STEP
トリガー設定

祝日リストの更新タイミングは、毎年 12 月 01 日に設定したいと思います。

しかし Google Apps Script トリガー設定機能における「時間主導型」設定では、「毎月 ◯◯ 日」の定期実行がもっとも長い周期となっています。

gas-holidays_007
トリガー設定画面

そのためトリガー上では「毎月 01 日」に実行するよう設定し、スクリプトの方では実行月が 12 月でなければ処理を終了するというガード節で対応したいと思います。

また実行タイミングでは「今年 12 月 01 日から来年 12 月 31 日まで」の年間有給情報をすべて取得し、”2.” のシート内データを一旦クリアしてから貼り付けるという処理をおこないます。

コード

Google Apps Scirpt のスクリプト エディターは、セットした gs ファイルを 上から順番に読み込む 仕様です。以下は、スクリプト エディターにセットする順番でコードを紹介しています。

main

トリガーとして設定するメイン ファンクションです。

/**
 * トリガーアカウント: 任意
 * 実行スクリプト:updateHolidays
 * トリガーイベント:例: 時間主導型 / 月ベースのタイマー / 1日 / 午前 0 時~1 時
 */
function updateHolidays(e) {
  const tte = new TriggerTimeEvents(e);
  if (tte.month !== 12) return;
  const holiday = new HolidayCalendar(tte.year);
  const holidayValues = holiday.getValues();
  const sheet = new Sheet();
  sheet.setValuesHeaderRowsAfter(holidayValues);
}

9 行目: 12 月以外の実行月は、処理をおこなわないよう判定しています。

TriggerTimeEvents クラス

時間主導型のトリガー イベントに関する「TriggerTimeEvents クラス」を設計します。

本クラスの詳細については、以下の記事を参照してください。

class TriggerTimeEvents {
  /**
   * 時間主導型のトリガー イベントに関するコンストラクタ
   * @constructor
   * @param {Object} e - 時間主導型のトリガー イベント オブジェクト
   */
  constructor(e) {
    /** @type {number} */
    this.year = e.year;
    /** @type {number} */
    this.month = e.month;
    /** @type {number} */
    this.date = e['day-of-month'];
    /** @type {number} */
    this.hour = e.hour;
    /** @type {number} */
    this.minute = e.minute;
    /** @type {number} */
    this.second = e.second;
    /** @type {string} NOTE: UTC 以外の値が取れるか不明 */
    this.timezone = e.timezone;
  }
  /**
   * 現地時間を取得するメソッド
   * @param {number} diffHours - 時差
   * @return {Date} 時差を調整した日時
   * NOTE: this.timezone が UTC でない場合 (JST であると仮定した) の処理あり
   */
  getLocaleDate(diffHours = 9) {
    if (this.timezone !== 'UTC') return this.getDate();
    const date = this.getDate();
    date.setHours(date.getHours() + diffHours);
    return date;
  }
  /**
   * 時間主導型のトリガーが実行された時間を取得するメソッド
   * @return {Date} 時間主導型のトリガーが実行された日時
   * NOTE: 確認されている状況では UTC の値が設定されている
   */
  getDate() {
    const date = new Date(
      this.year,
      this.month - 1,
      this.date,
      this.hour,
      this.minute,
      this.second
    );
    return date;
  }
}

HolidayCalendar クラス

祝日情報に関する「HolidayCalendar クラス」を設計します。

以下の処理がおこなえるようメソッドを用意します。

  • Google カレンダー「日本の祝日」情報にアクセスし、今年 12 月 01 日から来年 12 月 31 日までの祝日情報を取得する
  • 会社の指定休業日を定義する
  • Google スプレッドシートに貼り付けられるよう、これらの休日情報をまとめて二次元配列化する
/**
 * 祝日情報に関するクラス
 */
class HolidayCalendar {
  /**
   * 祝日情報に関するコンストラクタ
   * @constructor
   * @param {number} year - 対象となる年
   * @param {CalendarApp.Calendar} calendar - 祝日カレンダー 
   */
  constructor(year, calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com')) {
    /** @type {number} */
    this.year = year;
    /** @type {CalendarApp.Calendar} */
    this.calendar = calendar;
  }
  /**
   * Class CalendarApp から委譲されたメソッド
   * NOTE: https://developers.google.com/apps-script/reference/calendar/calendar-app
   */
  getEvents(...args) { return this.calendar.getEvents(...args); }
  /**
   * 祝日名と日付を取得するメソッド
   * @param {Date} startDate - 開始日
   * @param {Date} endDate - 終了日
   * @return {Array.<Array.<string|Date>>} 祝日名と日付の値
   */
  getValues(startDate = new Date(this.year, 11, 1), endDate = new Date(this.year + 1, 11, 31)) {
    const events = this.getEvents(startDate, endDate);
    const publicHolidayValues = events.map(event => [event.getTitle(), Datetime.format(event.getStartTime())]);
    const specificHolidaysValues = this.getSpecificHolidaysValues();
    const values = [...publicHolidayValues, ...specificHolidaysValues];
    values.sort((a, b) => a[1].localeCompare(b[1], 'ja'));
    return values;
  }
  /**
   * 固有の休暇を配列で取得するメソッド
   * @param {number} year - 対象となる年
   * @return {Array.<Array.<string>>} 固有の休暇
   */
  getSpecificHolidaysValues(year = this.year + 1) {
    const specificHolidaysValues = [
      ['冬季休暇', year - 1 + '/12/29'],
      ['冬季休暇', year - 1 + '/12/30'],
      ['冬季休暇', year - 1 + '/12/31'],
      ['冬季休暇', year + '/01/02'],
      ['冬季休暇', year + '/01/03'],
      ['冬季休暇', year + '/01/04'],
      ['夏季休暇', year + '/08/13'],
      ['夏季休暇', year + '/08/14'],
      ['夏季休暇', year + '/08/15'],
      ['冬季休暇', year + '/12/29'],
      ['冬季休暇', year + '/12/30'],
      ['冬季休暇', year + '/12/31'],
    ];
    return specificHolidaysValues;
  }
}

Sheet クラス

シートに関するクラス「Sheet クラス」を設計します。

以下の処理がおこなえるようメソッドを用意します。

  • 祝日情報を更新する際に、アクティブなシート (シート「祝日」) を参照する
  • アクティブ シートのヘッダーは残し、ヘッダー行よりも下のレコード部分をすべて削除する
  • 「HolidayCalendar クラス」で生成された二次元配列をレコード部分に貼り付ける
class Sheet {
  /**
   * シートに関するコンストラクタ
   * @constructor
   * @param {SpreadsheetApp.sheet} sheet - 対象となるシート
   * @param {number} headerRows - ヘッダー行の数
   */
  constructor(sheet = SpreadsheetApp.getActiveSheet(), headerRows = 1) {
    /** @type {SpreadsheetApp.Sheet} */
    this.sheet = sheet;
    /** @type {number} */
    this.headerRows = headerRows;
  }
  /**
   * Class Sheet から委譲されたメソッド
   * NOTE: https://developers.google.com/apps-script/reference/spreadsheet/sheet
   */
  getDataRange() { return this.sheet.getDataRange(); }
  getRange(...args) { return this.sheet.getRange(...args); }
  /**
   * レコードをすべて削除し、値を貼り付けるメソッド
   * @param {Array.<Array.<number|string|boolean|Date>>} values - 貼り付ける値
   */
  setValuesHeaderRowsAfter(values) {
    this.clearDataValues();
    if (values.length === 0) return;
    this.getRange(this.headerRows + 1, 1, values.length, values[0].length).
      setValues(values);
    return this;
  }
  /**
   * レコードをすべて削除するメソッド
   */
  clearDataValues() {
    const values = this.getDataValues();
    if (values.length === 0) return;
    this.getRange(1 + this.headerRows, 1, values.length, values[0].length).
      clearContent();
    return this;
  }
  /**
   * ヘッダー行を除いたレコード部分を取得するメソッド
   * @return {Array.<Array.<number|string|boolean|Date>>} レコード
   */
  getDataValues() {
    if (this.dataValues_ !== undefined) return this.dataValues_;
    const values = this.getDataRangeValues();
    const dataValues = values.filter((_, i) => i >= this.headerRows);
    this.dataValues_ = dataValues;
    return dataValues;
  }
  /**
   * シートの値すべて取得するメソッド
   * @return {Array.<Array.<number|string|boolean|Date>>} シートの値
   */
  getDataRangeValues() {
    if (this.dataRangeValues_ !== undefined) return this.dataRangeValues_;
    const dataRangeValues = this.getDataRange().getValues();
    this.dataRangeValues_ = dataRangeValues;
    return dataRangeValues;
  }
}

Datetime クラス

日時情報に関するクラス「Datetime クラス」を設計します。

以下の処理がおこなえるようメソッドを用意します。

  • Google カレンダー「日本の祝日」から取得した祝日の日付情報をyyyy/MM/ddに文字列化します
class Datetime {
  /**
   * 指定のフォーマットで日付を文字列化する静的メソッド
   * @param {Date} d - Date オブジェクト 文字列型も可
   * @param {string} format - フォーマットする形式
   * @return {string} フォーマットされた文字列型の日付
   */
  static format(d = new Date(), format = 'yyyy/MM/dd') {
    const date = new Date(d);
    const strDate = Utilities.formatDate(date, 'JST', format);
    return strDate;
  }
  
}

global

スクリプト エディターのグローバル領域に記述する内容です。

/**
 * GitHub README.md
 * https://github.com/FrontWorks-Inc/blog_list-of-holidays
 */
/**
 * グローバル定数宣言
 */
/** @type {SpreadsheetApp.Spreadsheet} */
const SS = SpreadsheetApp.getActiveSpreadsheet();

Github リンク

GitHub
GitHub - FrontWorks-Inc/blog_list-of-holidays: First Version First Version. Contribute to FrontWorks-Inc/blog_list-of-holidays development by creating an account on GitHub.

祝日リスト シートの呼び出し方

さいごに、作成した祝日リストを実際に他のスプレッドシートで呼び出して使う方法をご紹介いたします。

新しいシートの任意セルに、IMPORTRANGE 関数 を仕込むことで祝日リストのシート内容を呼び出すことができます。

=IMPORTRANGE("祝日リストの URL","祝日!A1:B50")

gas-holidays_008

このように IMPORTRANGE 関数をつかえば、スプレッドシートから別のスプレッドシートの値を持ってくることができるので、とても便利ですね。

あとは煮るなり焼くなりお好きにどうぞ! 笑

まとめ

今回は GAS をつかった毎年自動更新される祝日リストの作り方をご紹介いたしました!

上でご紹介した 祝日リストのマスターシートを作成し、IMPORTRANGE 関数で呼び出す方法 は、予定表関係のスプレッドシートを触るときに大活躍するので、とってもおすすめです💡

また今回見ていただきましたとおり「人が定期的におこなう必要があるちょっとしたシート更新・メンテナンス作業」こそ、GAS の本領発揮 です!

「祝日リストを更新する」というほんのちょっとした作業ですが、このようなタスクは自動化していかないと 塵も積もれば山となる で、気づいたときには保守作業に追われている毎日なんてことも。

未来の自分、そしてチームがいかに楽できるか を思い描きながら、日々のお仕事に GAS を役立ていきましょう! 🚀

関連記事

本記事でつくった祝日リストが大活躍する日付関数レシピを大公開! ぜひこちらの記事もチェックしてみてください。



gas-holidays_featured image

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

くのーるです! 下町生まれ、下町育ちの江戸っ子 🗼 から静岡県浜松市に I ターン

フロント・ワークスで取締役情報システム担当役員 & 東京通信大学 (TOU) 情報マネジメント学部で社会人大学生をしています。

また最近は ChatGPT や Midjourney, Stable Diffusion などのジェネレーティブ AI を楽しんでおり、社会人向けコミュニティの運営活動を個人でおこなっています 👇

🧙‍♂️ Discord コミュニティ「みなラボ ~みならい魔法使いたちの AI/PE Lab. ~」 🔮
discord.gg/bg5hrQXuMP

目次