📝

Googleカレンダーの予定を日報用に書き出してくれるSlack Appをつくった

に公開

Googleカレンダーの予定を日報用に書き出してくれるSlack Appをつくりました

日報を書くのは地味に時間がかかりますよね。
中でもGoogleカレンダーを見ながら人力で予定タイトルと作業にかかった時間を書き出すのは、地味に手間がかかります。人力なので、記入漏れや計算ミスもあります。
そろそろ日報を書くという頃に今日の作業時間まとめがSlackに通知されてきたら幸せですよね?GAS(Google Apps Script)を使ってGoogleカレンダーに記入している作業内容と時間をまとめて出力できるSlack Appの作り方を紹介します。

作成の流れ

  1. Googleスプレッドシートの準備
  2. Apps Scriptプロジェクトの作成
  3. スプレッドシート書き込みの動作確認
  4. Slack Appの作成とWebhook URL発行
  5. Apps ScriptのSlack連携設定
  6. Slack投稿の動作確認
  7. 自動化(トリガー設定)

1. Googleスプレッドシートの準備

  1. Googleドライブで新規スプレッドシートを作成します。
  2. シート1になっているシート名をDailyReport(例)に変更します。
  3. A1~D1 に以下の項目を入力します。
    -- A B C D
    1 開始時刻 終了時刻 タイトル 所要時間(h)

2. Apps Scriptプロジェクトの作成

  1. スプレッドシート上部メニュー → 拡張機能 → Apps Script を開きます。
  2. 以下のコードを Code.gs に貼り付けます。
    デフォルト以外のカレンダーを利用する場合、カレンダーIDの確認方法
    1. Googleカレンダーを開きます。
      1. 左側の「マイカレンダー」または「他のカレンダー」から対象のカレンダー名にカーソルを合わせ、︙(縦三点メニュー)をクリックして「設定と共有」を開きます。
        1. 下にスクロールすると「カレンダーの統合」という項目があり、その中に「カレンダーID」が表示されます。
    // スプシに書き込む
    function exportTodayToSheet() {
      const SHEET_NAME = 'DailyReport';
      const ss    = SpreadsheetApp.getActiveSpreadsheet();
      const sheet = ss.getSheetByName(SHEET_NAME);
      if (!sheet) throw new Error(`シート「${SHEET_NAME}」が見つかりません`);
      
      // 既存データクリア(2行目以降)
      sheet.getRange('A2:D').clearContent();
      
      // 今日のイベント取得
      const today     = new Date();
      // デフォルトのカレンダーを利用する場合
      const calendar = CalendarApp.getDefaultCalendar();
      // デフォルト以外のカレンダーを利用する場合(カレンダーIDを指定)
      // const calendar = CalendarApp.getCalendarById('your_calendar_id@group.calendar.google.com');
    
      const events    = calendar.getEventsForDay(today);
      const tz        = Session.getScriptTimeZone();
      
      const summary = {};
      
      events.forEach(ev => {
        const title = ev.getTitle() || '(無題)';
        const duration = (ev.getEndTime() - ev.getStartTime()) / (1000 * 60 * 60); // h
        // タイトルごとに時間を統合
        if (!summary[title]) {
          summary[title] = {
            totalDuration: 0,
            firstStart: ev.getStartTime(),
            lastEnd: ev.getEndTime()
          };
        } else {
          if (ev.getStartTime() < summary[title].firstStart) {
            summary[title].firstStart = ev.getStartTime();
          }
          if (ev.getEndTime() > summary[title].lastEnd) {
            summary[title].lastEnd = ev.getEndTime();
          }
        }
        summary[title].totalDuration += duration;
      });
    
      // スプレッドシートへ出力
      Object.entries(summary).forEach(([title, data]) => {
        sheet.appendRow([
          Utilities.formatDate(data.firstStart, tz, 'HH:mm'),
          Utilities.formatDate(data.lastEnd, tz, 'HH:mm'),
          title,
          data.totalDuration.toFixed(2)
        ]);
      });
    
      let msg = Object.entries(summary).length
        ? Object.entries(summary)
            .map(([title, data]) => `- ${title} ${data.totalDuration.toFixed(2)}h`)
            .join('\n')
        : '本日の予定はありません。';
      
      postToSlack(`*今日の作業*\n${msg}`);
    }
    
    function postToSlack(text) {
      const url = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
      if (!url) throw new Error('SLACK_WEBHOOK_URL が未設定です');
      
      const payload = {
        text: text,
        mrkdwn: true    // Markdown を使う場合は true
      };
      
      const options = {
        method: 'post',
        contentType: 'application/json',
        payload: JSON.stringify(payload)
      };
      
      UrlFetchApp.fetch(url, options);
    }
    
    

3. スプレッドシート書き込みの動作確認

手順2まで行った時点でexportTodayToSheet関数は最後に記載しているpostToSlack関数以外動作します。スプレッドシートを作成したアカウントのデフォルトカレンダーの今日の予定が書き出されているか、確認してみましょう。

  1. postToSlack関数の設定はまだ行っていないので、以下のようにコメントアウトします。
    // postToSlack(`*今日の作業*\n${msg}`);
    
  2. エディタ上部の「▶実行」ボタンでexportTodayToSheet関数を実行します。
  3. 初回は権限の承認を求めるページが表示されます。指示に従ってアクセスを許可し、以下のような画面になったら詳細を表示 > ~~~(安全ではないページ)に移動 を押します。
  4. スプレッドシートに今日の予定が出力されていれば成功です 🎉

同じタイトルの予定があれば、タイトルと所要時間は統合されるようになっています!幸せだ!

4. Slack Appの作成とWebhook URL発行

Slack App作成の最新の手順は公式ドキュメントをご覧ください。
https://api.slack.com/quickstart

Webhookって何?

Webhookは、あるサービスで特定のイベントが起きたときに、あらかじめ設定した別のサービスに自動で通知を送ってくれる仕組みです。今回は、GASからSlackにメッセージを送るために使います。

Slack Appの作成

  1. https://api.slack.com/apps にアクセスして、「Create New App」→「From scratch」でアプリを作成します。
  2. 左サイドバー → “Incoming Webhooks” をクリックします。
  3. “Activate Incoming Webhooks”(有効化)に切り替えます。

Webhook URL発行

  1. 画面下部「Add New Webhook to Workspace」 ボタンを押します。
  2. ポップアップで投稿先のチャンネルを選択し、許可するをクリックします。
  3. 成功すると「Webhook URL」が発行されるので、コピーしておきます。
     https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
    

Slack Appをカスタマイズしたい場合

左サイドバー → "Basic Information"から、Display Informationで表示名やアイコンを編集できます。

5. Apps ScriptのSlack連携設定

  1. Apps Scriptエディタの左サイドバーにある歯車アイコン(プロジェクトの設定)をクリックします。
  2. スクリプト プロパティに以下を追加して保存します。
    プロパティ: SLACK_WEBHOOK_URL
    値:(コピーした Webhook URL)

6. Slack投稿の動作確認

  1. 手順3でpostToSlack関数をコメントアウトしている場合は、外します。
  2. エディタ上部の「▶実行」ボタンでexportTodayToSheet関数を実行します。
  3. 手順3と同様に権限の承認を求めるページが表示されるので、指示に従って進みます。
  4. 指定したチャンネルにメッセージが届けば成功です。

あとは自動トリガーと組み合わせれば、毎日決まった時間に今日の作業まとめをslackに流してもらうことが可能になります!やったー!👏

7. 自動化(トリガー設定)

  1. Apps Scriptエディタの左サイドバーにある時計アイコン(トリガー) をクリックします。
  2. 「トリガーを追加」
    • 関数:exportTodayToSheet
    • イベントのソース:時間主導型
    • タイマー:(毎日で良い場合)日付ベースのタイマー /(特定の曜日に欲しい場合)週ベースのタイマー → 任意の曜日を選択 ※曜日ごとの設定を増やせば平日のみ通知等が可能
    • 時間帯:任意の時間帯を選択

保存すると自動でSlackに通知が飛んでくるようになります!

おわりに

これでヒューマンエラーとおさらば!Chat GPTありがとう!

最後までお読みいただき、ありがとうございました。

参考記事

本記事で使用している画像の一部は下記の自分が書いた過去の記事で使用している画像を流用しています。
GAS(Google Apps Script)でGoogleカレンダーの予定に特定の文字が含まれていたらSlackに通知する

Discussion