KEIS BLOGは株式会社ケイズ・ソフトウェアが運営しています。

KEIS BLOG

ChatGPTに聞きながらランダム指名Slack botを作った話(後編)


後編です!

さて、ここまでちゃっぴーに作ってもらったところで、GASのトリガーについて考えていきます。
今回作ってもらって、定期的に動かしたい関数は3つ。

  • notifyRandomEmployee:Slackにメッセージを投下するメインの関数
  • createTrigger:notifyRandomEmployee関数のトリガーを作成する関数(chatGPTは、「初回実行時に手動で設定する必要あり」とコメントしていますね。)
  • importJapaneseHolidays:祝日をスプレッドシートにインポートする関数

気をつけたいことは、GASのトリガーって、毎日9:30 という設定ができないんですよね。

GASのGUIから確認しても、日付ベース(毎日)のトリガーだと一時間ごとにしか選択できません。これだと、「9時〜10時の間のどこか」で「指名されるかもしれない…」というナゾのドキドキ感を味わうことになります。
ちゃっぴーが書いてきた以下のコードも、実は9:30前後(おそらく前後15分?)に実行されるっていう引っ掛けコードです。(nearMinuteと言っています。。)

1function createTrigger() {
2ScriptApp.newTrigger('notifyRandomEmployee')
3.timeBased()
4.atHour(9)
5.nearMinute(30)
6.everyDays(1)
7.create();
8}

9:30ぴったりに実行したかったので、このコードを変更することにします。
ググったら結構みんな同じことで悩んでいるようで、毎日「特定の日時」に実行されるトリガーを作成する、という方法でハックしてるみたいです。先人たちにならい、以下のようにcreateTrigger関数を変更しました。

1// トリガーのセットアップ(毎日決まった時間に実行)
2function createTrigger() {
3  var allTriggers = ScriptApp.getProjectTriggers();
4  var existingTrigger = null;
5 
6  // すでに存在するnotifyRandomEmployeeトリガーを探す
7  for (var i = 0; i < allTriggers.length; i++) {
8    if (allTriggers[i].getHandlerFunction() === 'notifyRandomEmployee') {
9      existingTrigger = allTriggers[i];
10      break;
11    }
12  }
13 
14  // すでに存在するトリガーがあれば削除
15  if (existingTrigger !== null) {
16    ScriptApp.deleteTrigger(existingTrigger);
17  }
18 
19  var triggerDay = new Date();
20    triggerDay.setDate(triggerDay.getDate() + 1);
21    triggerDay.setHours(9);
22    triggerDay.setMinutes(30);
23    triggerDay.setSeconds(0);
24 
25  ScriptApp.newTrigger('notifyRandomEmployee')
26    .timeBased()
27    .at(triggerDay)
28    .create();
29}

この関数は、毎日10時〜11時のどこかで実行するようにセットしました。
notifyRandomEmployeeを翌日9:30にセットしてくれます。かつ、実行済みの古いnotifyRandomEmployeeのトリガーがあれば削除してくれます。
これで3つのうちの2つの関数はトリガーが定まりました。

残すはimportJapaneseHolidaysですが、これは正直いつでもいい。年一でもいいので、手動で実行するでも全然いい。でも、せっかくだしな〜ということで、ちゃっぴーに以下のお願いをしてコードを書き換えてもらいました。

毎月1日の0時に定期実行するようにするから、当月の祝日リスト取得に直して

できたものはこちら

1function importJapaneseHolidays() {
2  const calendarId = 'ja.japanese.official#holiday@group.v.calendar.google.com'; // 日本の祝日カレンダーID
3  const today = new Date();
4   
5  // 当月の1日
6  const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
7  // 翌月の1日
8  const startOfNextMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1);
9 
10  // 当月の祝日を取得
11  const events = CalendarApp.getCalendarById(calendarId).getEvents(startOfMonth, startOfNextMonth);
12 
13  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(HOLIDAY_SHEET_NAME);
14  if (!sheet) {
15    throw new Error('祝日シートが見つかりません');
16  }
17 
18  // シートをクリアして、新しいデータを追加
19  sheet.clear();
20  sheet.getRange(1, 1).setValue('祝日');
21 
22  // 祝日を1列目に書き込む(日本時間に変換)
23  events.forEach((event, index) => {
24    const startTime = event.getStartTime();
25     
26    // タイムゾーンを日本時間に変更して日付を取得
27    const dateInJapan = Utilities.formatDate(startTime, Session.getScriptTimeZone(), 'yyyy-MM-dd');
28     
29    sheet.getRange(index + 2, 1).setValue(dateInJapan);
30  });
31}

いいね!

というわけで、importJapaneseHolidaysは毎月1日の0〜1時の間に動いています。
メッセージやアイコンを自分好みに直したら、完成です!

こまかい話ですが、最初にちゃっぴーに書いてもらったnotifyRandomEmployee内ではJSTの考慮がなされていないので、つい先日の祝日は誤って実行されてしまいました。ごめんよ、指名されてしまった人。現在は修正したので祝日には実行されないです。

 

まとめ

Slackリマインダー、便利なんですが、+αなにかしたい、というときに良いツールがほしいなと思ってたんですよね。
今回GASに触れたことで、大分ハードルが下がりました。ちゃっぴーのサポートも手厚いですし、積極的に使っていきたいと思います。
Enjoyプロンプトライフ!