Googleカレンダーから空き時間を取得するGAS | GASおじさんのブログ
GASのTips

Googleカレンダーから空き時間を取得するGAS

空き時間を取得 GASのTips

みなさんこんにちは!GASおじさんです。

今回はGoogleカレンダーから空き時間を取得するスクリプトをご紹介します。

Youtubeでも解説していますので動画で見たい人は以下からどうぞ。

Googleカレンダーから空き時間を取得するスクリプト

スクリプトの実装

まずは以下3つのスクリプトをコピペしてください。

①グローバル変数

const CALENDAR_ID = 'example@gmail.com'; // カレンダーIDを指定
const AT_LEAST_MINUTES = 60; // 少なくとも確保したい時間を「分」で指定
const WORKTIME = {
  START: {
    HOURS: 9, MINUTES: 30, // 勤務開始時間の「時」「分」を指定
  },
  END: {
    HOURS: 18, MINUTES: 0, // 勤務終了時間の「時」「分」を指定
  }
};
const DAYS = ['日', '月', '火', '水', '木', '金', '土'];
  • CALENDAR_IDで空き時間を抽出したいカレンダーのIDを指定してください。
  • AT_LEAST_MINUTESで少なくとも確保したい時間を「分」で指定してください。上記は少なくとも空き時間が60分以上ある場合に空き時間として抽出するサンプルです。
  • WORKTIMEの各数値を指定してください。上記は9:30勤務開始、18:00勤務終了の場合のサンプルです。

②getFreeTimeList関数

/**
 * 特定の日付の空き時間を配列で取得する関数
 * @param {Date} date - 日付
 * @returns {Object[]} - 空き時間オブジェクトの配列
 */
function getFreeTimeList(date=new Date()) {
  const calendar = CalendarApp.getCalendarById(CALENDAR_ID);
  const worktime = {
    start: new Date(
      date.getFullYear(), date.getMonth(), date.getDate(), 
      WORKTIME.START.HOURS, WORKTIME.START.MINUTES
    ),
    end: new Date(
      date.getFullYear(), date.getMonth(), date.getDate(), 
      WORKTIME.END.HOURS, WORKTIME.END.MINUTES
    ),
  };

  const events = calendar.getEvents(worktime.start, worktime.end).filter(e => {
    const hours = (e.getEndTime() - e.getStartTime())/1000/60/60;
    return hours < 24; // 終日イベントを除外
  });

  // 重複イベントを結合した仮想イベントを作成
  const virtualEvents = createVirtualEvents(calendar, events);

  let freeTimeList = [];

  if(virtualEvents.length == 0){
    const freeTime = {start: worktime.start, end: worktime.end};
    freeTimeList.push(freeTime);
  }

  if(virtualEvents.length == 1){
    const event = virtualEvents[0];
    const freeTime1 = {start: worktime.start, end: event.start};
    const freeTime2 = {start: event.end, end: worktime.end};
    freeTimeList.push(freeTime1, freeTime2);
  }

  if(virtualEvents.length >= 2){
    for(let i = 0; i < virtualEvents.length; i++){
      const event = virtualEvents[i];
      if(i == 0){
        // 勤務開始時間から最初のイベントまでの空き時間を追加
        const freeTime = {start: worktime.start, end: event.start};
        freeTimeList.push(freeTime);
      }else{
        // イベントとイベントの間の空き時間を追加
        const prevEvent = virtualEvents[i-1];
        const freeTime = {start: prevEvent.end, end: event.start};
        freeTimeList.push(freeTime);
      }

      if(i == virtualEvents.length-1){
        // 最後のイベントから勤務終了時間までの空き時間を追加
        const freeTime = {start: event.end, end: worktime.end};
        freeTimeList.push(freeTime);
      }
    }
  }

  // 指定の時間(分)より少ないものを除外する
  freeTimeList = freeTimeList.filter(freeTime => {
    const minutes = (freeTime.end - freeTime.start)/1000/60;
    return minutes >= AT_LEAST_MINUTES;
  });
  
  return freeTimeList;
}

③createVirtualEvents関数

/**
 * 終日イベントを除外し、重複イベントを結合した仮想イベントを作成する関数
 * @param {CalendarApp.Calendar} calendar - カレンダーオブジェクト
 * @param {Date[]} events - イベントオブジェクトの配列
 * @returns {Object[]} 仮想イベントの配列
 */
function createVirtualEvents(calendar, events) {
  const virtualEvents = [];
  for(const event of events){
    // 重複イベントがあるかどうかを確認
    const eventsInEvent = calendar.getEvents(event.getStartTime(), event.getEndTime()).filter(e => {
      const hours = (e.getEndTime() - e.getStartTime())/1000/60/60;
      return  hours < 24; // 終日イベントを除外
    });

    if(eventsInEvent.length == 1){
      // 重複イベントがない場合は、そのまま追加
      const virtualEvent = {start: event.getStartTime(), end: event.getEndTime()};
      virtualEvents.push(virtualEvent);
    }else{
      // 重複イベントがある場合は、開始時間の最小値と終了時間の最大値を計算して1個の仮想イベントを作成
      const firstEvent = eventsInEvent.reduce((a, b) => a.getStartTime() < b.getStartTime() ? a : b);
      const lastEvent = eventsInEvent.reduce((a, b) => a.getEndTime() > b.getEndTime() ? a : b);
      const virtualEvent = {start: firstEvent.getStartTime(), end: lastEvent.getEndTime()};

      // 生成する配列をユニークにする
      const jsonEvents = JSON.stringify(virtualEvents);
      const jsonEvent = JSON.stringify(virtualEvent);
      if(!jsonEvents.includes(jsonEvent)) virtualEvents.push(virtualEvent);
    }
  }
  return virtualEvents;
}

スクリプトの検証

上記3つのスクリプトをコピペしたら、Googleカレンダーに適当な予定を入れて、getFreeTimeList関数の動きを検証してみましょう。

Googleカレンダーは以下のような状態です。

11月1日の12:00〜14:00に予定を入れました。

この状態で以下のmyFunction関数を定義し実行してみます。その際、getFreeTimeList関数の引数に11月1日を指定しています。

function myFunction() {
  const date = new Date(2024, 10, 1); // 特定の日付を指定
  const freeTimeList = getFreeTimeList(date);
  console.log(freeTimeList);
}

実行結果は以下のようになりました。

無事、

  • 2024年11月1日 9:30〜12:00
  • 2024年11月1日 14:00〜18:00

という、2つの空き時間を抽出してくれました。

使用例1: スプレッドシートに入力

今日の日付から向こう7日分の空き時間を抽出して、スプレッドシートに入力します。

スプレッドシートを起動し、コンテナバインドスクリプトに以下のコードをコピペして実行します(シート名は必要に応じて書き換えてください)。

function setFreeTimeToSheet() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  const now = new Date();
  const y = now.getFullYear();
  const m = now.getMonth();
  const d = now.getDate();
  for(let i = 0; i < 7; i++){
    const date = new Date(y, m, d+i);
    const freeTimeList = getFreeTimeList(date);
    let text = '';
    for(const freeTime of freeTimeList){
      const start = Utilities.formatDate(freeTime.start, 'Asia/Tokyo', 'H:mm');
      const end = Utilities.formatDate(freeTime.end, 'Asia/Tokyo', 'H:mm');
      text += `${start}〜${end}, `;
    }
    text = text.slice(0, -2); // 末尾のカンマを削除
    sheet.appendRow([date, text])
  }
}

実行結果は以下のとおりです。

※2024年10月30日時点の実行結果

使用例2: Gmailの下書きを作成

続けて、今日の日付から向こう7日分の空き時間を抽出して、Gmailの下書きを作成するスクリプトです。

function createDraft() {
  const now = new Date();
  const y = now.getFullYear();
  const m = now.getMonth();
  const d = now.getDate();
  let text = '';
  for(let i = 0; i < 7; i++){
    const date = new Date(y, m, d+i);
    const formatDate = Utilities.formatDate(date, 'Asia/Tokyo', `M月d日(${DAYS[date.getDay()]})`);
    text += `${formatDate} `;
    const freeTimeList = getFreeTimeList(date);
    if (freeTimeList.length == 0) text += '-  ';
    for(const freeTime of freeTimeList){
      const start = Utilities.formatDate(freeTime.start, 'Asia/Tokyo', 'H:mm');
      const end = Utilities.formatDate(freeTime.end, 'Asia/Tokyo', 'H:mm');
      text += `${start}〜${end}, `;
    }
    text = text.slice(0, -2); // 末尾のカンマを削除
    text += '\n';
  }

  const recipient = 'example@gmail.com';
  const subject = '空き時間';
  let body = `以下の時間でご都合いかがでしょうか?\n\n`;
  body += text;
  body += '\nご確認の程、よろしくお願いいたします。';
  GmailApp.createDraft(recipient, subject, body);
}

実行結果は以下のとおりです。

※2024年10月30日時点の実行結果

まとめ

以上、Googleカレンダーから空き時間を取得するスクリプトでした。

グローバル変数の値や取得する日数については、実際の環境に応じてカスタマイズしながらご利用ください。

コメント

タイトルとURLをコピーしました