Closed9

【GAS】Googleカレンダーに同期させる方法

yusukeyusuke

Googleスプレッドシートで作成したスケジュール表をGoogleカレンダーに同期したい。
手動でカレンダーにイベントを作成するのは面倒なので、GASで同期するようにした。

yusukeyusuke

手順はシンプルで

  • 指定したシートのデータを取得(開始時間、終了時間、メモなど)
  • そのデータに基づいたカレンダーイベント作成する
  • イベントIDをスプレッドシートに書き込む
yusukeyusuke

スプレッドシートは以下のような形式にしてる。
日時にはひとつのセルでも出来るけど、日時を変更するときに別々にした方が簡単なのと、時間がコピペしやすいので今回はこのようにしている。

title year month day start time end time description calendar id event id
my event 1 2022 4 8 9:30 10:00 some description example@gmail.com
my event 2 2022 4 10 13:30 14:30 some description example@gmail.com
yusukeyusuke

データを取得

function isCellData(e) {
  // 空のデータはいらない
  return e.join().replace(/,/g, '').length;
}

function scheduler() {
  // schedule というシートのデータを取得
  const scheduleSheet = SpreadsheetApp.getActive().getSheetByName('schedule');
  const scheduleList = scheduleSheet.getRange(2, 1, scheduleSheet.getLastRow(), 9).getValues().filter(isCellData);

  ...
}
yusukeyusuke

カレンダーイベントを作成

配列に格納されているカレンダー情報をループして、createEventでイベントを作成する。

function isCellData(e) {
  return e.join().replace(/,/g, '').length;
}

function scheduler() {
  const scheduleSheet = SpreadsheetApp.getActive().getSheetByName('schedule');
  const scheduleList = scheduleSheet.getRange(2, 1, scheduleSheet.getLastRow(), 9).getValues().filter(isCellData);

  for (const [index, schedule] of scheduleList.entries()) {
    const title = schedule[0];
    const year = schedule[1];
    const month = schedule[2];
    const day = schedule[3];
    const startTime = schedule[4];
    const endTime = schedule[5];
    const description = schedule[6];
    const calendarId = schedule[7];
    const calendar = CalendarApp.getCalendarById(calendarId);

    const startDateTime = new Date(`${year}-${month}-${day} ${startTime} GMT+9`);
    const endDateTime = new Date(`${year}-${month}-${day} ${endTime} GMT+9`);

    // 新しいイベントを作成
    calendar.createEvent(title, startDateTime, endDateTime, { description });
  }
}
yusukeyusuke

イベントIDをスプレッドシートに書き込む

イベントを編集した場合、カレンダーもアップデートしてほしいので、スプレッドシートにイベントIDを書き込む。もしイベントIDがあった場合、そのイベントを削除してから新しいイベントを作成する。

function isCellData(e) {
  return e.join().replace(/,/g, '').length;
}

function scheduler() {
  const scheduleSheet = SpreadsheetApp.getActive().getSheetByName('schedule');
  const scheduleList = scheduleSheet.getRange(2, 1, scheduleSheet.getLastRow(), 9).getValues().filter(isCellData);

  for (const [index, schedule] of scheduleList.entries()) {
    count = count + 1;

    const title = schedule[0];
    const year = schedule[1];
    const month = schedule[2];
    const day = schedule[3];
    const startTime = schedule[4];
    const endTime = schedule[5];
    const description = schedule[6];
    const calendarId = schedule[7];
    const eventId = schedule[8];
    const calendar = CalendarApp.getCalendarById(calendarId);

    if (eventId) {
      const existingEvent = calendar.getEventById(eventId);
      // 既存のイベントを削除してセルを空にする
      existingEvent.deleteEvent();
      scheduleSheet.getRange(2 + index, 9).setValue('');
    }

    const startDateTime = new Date(`${year}-${month}-${day} ${startTime} GMT+9`);
    const endDateTime = new Date(`${year}-${month}-${day} ${endTime} GMT+9`);
    calendar.createEvent(title, startDateTime, endDateTime, { description });

    // イベントIDを書き込む
    scheduleSheet.getRange(2 + index, 9).setValue(newEventId);
  }
}
yusukeyusuke

これはオマケですが、ログを表示すると見やすいので。

function isCellData(e) {
  return e.join().replace(/,/g, '').length;
}

// 日時をフォーマットする
function formatDate(date) {
  return Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy-MM-dd E HH:mm');
}

function scheduler() {
  let count = 0;

  const scheduleSheet = SpreadsheetApp.getActive().getSheetByName('schedule');
  const scheduleList = scheduleSheet.getRange(2, 1, scheduleSheet.getLastRow(), 9).getValues().filter(isCellData);

  for (const [index, schedule] of scheduleList.entries()) {
    count = count + 1;

    const title = schedule[0];
    const year = schedule[1];
    const month = schedule[2];
    const day = schedule[3];
    const startTime = schedule[4];
    const endTime = schedule[5];
    const description = schedule[6];
    const calendarId = schedule[7];
    const eventId = schedule[8];
    const calendar = CalendarApp.getCalendarById(calendarId);

    if (eventId) {
      const existingEvent = calendar.getEventById(eventId);

      existingEvent.deleteEvent();
      scheduleSheet.getRange(2 + index, 9).setValue('');
    }

    const startDateTime = new Date(`${year}-${month}-${day} ${startTime} GMT+9`);
    const endDateTime = new Date(`${year}-${month}-${day} ${endTime} GMT+9`);
    const newEvent = calendar.createEvent(title, startDateTime, endDateTime, { description });
    const newEventId = newEvent.getId();

    scheduleSheet.getRange(2 + index, 9).setValue(newEventId);

    const startAt = formatDate(newEvent.getStartTime());
    const endAt = formatDate(newEvent.getEndTime());

    // 新しいイベントの情報
    Logger.log(`New event created: ${title} at ${startAt} to ${endAt}, event ID: ${newEventId}`);
  }

  // 何イベント作成したか確認するように
  Logger.log(`Created ${count} schedules`);
}
yusukeyusuke

イベント開始日と終了日が1日以上の場合、上記ではできないので修正する必要がある。

このスクラップは2022/04/08にクローズされました