【ChatGPT】1週間の曜日別空き時間をSlackに投稿する【Googleカレンダー】

タスク管理をNotionで実施して、週次で稼働時間を40hとして実績工数を集計して差分を見ているのですが、

  • MTGや相談が突発的に発生して見積もり工数を圧迫して、空き稼働を見誤る
  • Slackやメール返信していて、実際にそこまで稼働できていない

という形で予実がずれることが多く毎週タスクが繰り越されることが重なったため、実際に稼働できる工数を見える化してみました。その際にとりあえず日別に空き時間がどれくらいあるかをぱっと分かればいいかなと思い、GASを使ってSlackに投稿したのでその流れを記載しておきます。

実際にSlackに送っているテキストはこんな感じです。簡易的ですが、何曜日がどれくらい空いているかなどSlackでぱっとわかり週単位でタスクを組むときには役に立っています。

目次

実施したこと

SlackのWebhook作成

botの通知を送るのに今回は手軽なwebhookを採用しました。方法は何でもいいですが、GASで送るだけならこの方法が一番簡単な気がしています。

やり方は検索すればたくさんでてくるのでここでは割愛します。

GASの作成

今回、要件としては以下のようなことを考えていました。意外と細かくなりました。

  • 曜日ごとの空き時間を知りたい
  • Goggleカレンダーの9時から18時までの空き時間の算出
  • 今週は日曜日スタート、土日は出力しない
  • 12-13時は昼休憩なので除外

自分で検索しながら作ってもいいのですが、業務効率化に時間を使うのも本末転倒なので今回はChatGPTに依頼をして作ってもらいましたが、プログラミング系はやりたいこと伝えるとかなり精度高いものが5分もかからずでてくるのでオススメです。

命令文

Googleカレンダーの今週の空いている予定が何時間あるか確認して、GASでslackに毎週出力する方法を教えて

##制約条件

曜日ごとの空き時間、かつ9時から18時までの空き時間の算出
曜日別の空き時間にプラスして、合計の空き時間も表示して
合計空き時間を最初のメッセージ、またどの週かわかるようにstart->endの日付も追記
今週は日曜日スタート、土日は出力しない
空き時間=カレンダーが入っていない時間
カレンダーに入っている時間も合わせて出力して
予定がある時間は時間が被っていたらユニーク時間に
12-13時は昼休憩なので除外

実際に出てきたアウトプットから少しChatGPTとやりとりをして手直しをしたものがこちらです。冒頭の

var calendarId = 'example@gmail.com'; // プライマリーカレンダーを使用
var slackWebhookUrl = 'https://hooks.slack.com/services/…'; // SlackのIncoming Webhook URL

については先程発行したwebhookのURLと計算させたいカレンダーのidを入力してください。

function postAvailableAndBusyHoursToSlack() {
  var calendarId = 'example@gmail.com'; // プライマリーカレンダーを使用
  var slackWebhookUrl = 'https://hooks.slack.com/services/...'; // SlackのIncoming Webhook URL
  var now = new Date();
  var startOfWeek = new Date(now.setDate(now.getDate() - now.getDay() + 1)); // 週の開始(日曜日)
  startOfWeek.setHours(0, 0, 0, 0);
  var endOfWeek = new Date(startOfWeek);
  endOfWeek.setDate(endOfWeek.getDate() + 5); // 金曜日まで(土日を含まない)
  endOfWeek.setHours(23, 59, 59, 999);

  var events = CalendarApp.getCalendarById(calendarId).getEvents(startOfWeek, endOfWeek);
  var dayHours = {}; // 日付ごとの予定時間と空き時間を保持するオブジェクト
  var totalAvailableHours = 0;

  for (var day = 1; day <= 5; day++) { // 月曜日から金曜日までループ
    var currentDate = new Date(startOfWeek);
    currentDate.setDate(currentDate.getDate() + day - 1);
    var formattedDate = Utilities.formatDate(currentDate, Session.getScriptTimeZone(), 'MM/dd') + '(' + ['日', '月', '火', '水', '木', '金', '土'][currentDate.getDay()] + ')';
    dayHours[formattedDate] = {
      'busyHours': 0,
      'availableHours': 8 * 2 // 昼休憩1時間を引いて8時間、30分単位なので倍にする
    };
  }

  events.forEach(function(event) {
    var eventStartTime = event.getStartTime();
    var eventEndTime = event.getEndTime();
    var eventDate = Utilities.formatDate(eventStartTime, Session.getScriptTimeZone(), 'MM/dd') + '(' + ['日', '月', '火', '水', '木', '金', '土'][eventStartTime.getDay()] + ')';
    if (eventDate in dayHours) {
      var startTime = Math.max(9 * 2, eventStartTime.getHours() * 2 + Math.floor(eventStartTime.getMinutes() / 30));
      var endTime = Math.min(18 * 2, eventEndTime.getHours() * 2 + Math.ceil(eventEndTime.getMinutes() / 30));
      if (startTime < 24 && endTime > 26) { // 昼休憩を考慮(12時から13時)
        endTime -= 2; // 昼休憩1時間を引く
      }
      if (endTime > startTime) { // 有効な予定時間のみを考慮
        dayHours[eventDate].busyHours += (endTime - startTime) / 2;
        dayHours[eventDate].availableHours -= (endTime - startTime);
      }
    }
  });

  // Slackに投稿するメッセージの作成
  var message = '今週の空き時間と予定時間 (' + Utilities.formatDate(startOfWeek, Session.getScriptTimeZone(), 'MM/dd') + ' - ' + Utilities.formatDate(endOfWeek, Session.getScriptTimeZone(), 'MM/dd') + '):\n';
  for (var date in dayHours) {
    var availableHours = dayHours[date].availableHours / 2; // 30分単位を時間に変換
    totalAvailableHours += availableHours;
    message += date + ': 空き時間 ' + availableHours.toFixed(1) + '時間';
    if (dayHours[date].busyHours > 0) {
      message += '、予定時間: ' + dayHours[date].busyHours.toFixed(1) + '時間';
    }
    message += '\n';
  }
  message += '合計空き時間: ' + totalAvailableHours.toFixed(1) + '時間\n';

  // Slackにメッセージを投稿
  UrlFetchApp.fetch(slackWebhookUrl, {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify({'text': message})
  });
}

このスクリプトは、月曜日から金曜日までの各日について、その日の予定がある時間(busyHours)と利用可能な空き時間(availableHours)を計算しています。

また、各日の利用可能な空き時間と予定がある時間を30分単位で計算して、空き時間と予定がある時間は0.5時間単位で出力しています。(.toFixed(1)を使用して小数点第一位まで表示)

昼休憩の時間(12時から13時)は利用可能な時間から自動的に除外されていたり、各日付は「MM/dd(E)」形式で表示されるようになっていたりと細かいところもChatGPTとのやりとりで簡単に修正できました。便利。

GASの動作確認&トリガー設定

あとはGASの画面に貼り付けて動作確認をして問題ないか確認します。無事にSlackに通知が飛べば問題なし。

トリガーは週単位で集計しているので、いつも週報を更新する日曜or月曜に見えるようにしたいので「毎週日曜日AM09:00」で設定しました。

今後改善するなら

今回はSlackに投稿していますが、タスク管理や週報はNotionのDatabaseで作成して運用しているのでNotionAPIを使って自動でNotionに入るかもためしていきたいところ。

ただSlackに流れたほうが通知も飛んでリマインドにもなるのでやるとしても「Googleカレンダー→Notion→Slack」で間に挟む形に変えれたらとは思っています。

まとめ

今回はChatGPTに作成してもらいましたが、業務効率化のプログラミングは時間かけたくない&自分の手元で動けばいいことも多く重宝する気がします。今後も試しつつ使えそうなアウトプットがでてきたら残していきます。

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