自前の GAS カレンダースクリプトを整えたメモ 2026 年 6 月現在地

自前の GAS カレンダースクリプトを整えたメモ 2026 年 6 月現在地

自前の GAS カレンダースクリプトを整えたメモ 2026 年 6 月現在地 です。

背景

完全に毎週繰り返すイベントならいいんですけど、たまにイレギュラーが生じたりすると標準の Google カレンダー繰り返し登録だとやりづらい。

また学校の講師イベントのような表記が変わるのは結構しんどいので、そのための自分用 GAS で Google カレンダーにイベントを一括登録・削除するスクリプトを作って使ってます。

2026 年 6 月の現在地です。

準備

準備方法や使い方は書いておきますが、この記事が知見メモという感じですので、利用する際は自己責任でよろしくおねがいします。

  • Google Apps Script を開き、新しいプロジェクトを作成する
  • 下記のコードをエディタに貼り付けて保存する
  • 利用可能なカレンダーの一覧をログ出力 を実行し、ログに表示されたカレンダー名・ID を確認する
  • _list に確認したカレンダー名とIDを登録する
  • CALENDAR_TITLE に使いたいカレンダー名をセットする
  • events に登録したいイベントを入力する

実際のコード

/**
 * Google カレンダー一括登録・削除スクリプト
 *
 * 【初期設定(初回のみ)】
 * 1. 利用可能なカレンダーの一覧をログ出力() を実行してカレンダー名・ID を確認
 * 2. _list にカレンダー名と ID を登録
 * 3. CALENDAR_TITLE に使用するカレンダー名を設定
 *
 * 【スケジュール登録・削除時】
 * 1. events にイベント情報を入力
 * 2. description / location を必要に応じて設定
 * 3. スケジュール登録_試行() または スケジュール削除_試行() で内容確認
 * 4. 問題なければ スケジュール登録() / スケジュール削除() で本番実行
 */

// ▼ カレンダー名 → ID のマッピング(利用可能なカレンダーの一覧をログ出力() で確認)
const _list = {
  "カレンダー名1": "カレンダーID1",
  "カレンダー名2": "カレンダーID2",
  "カレンダー名3": "カレンダーID3",
};

// ▼ 登録・削除先カレンダー名
const CALENDAR_TITLE = "カレンダー名1";

// ▼ イベント一覧
const events = [
  // { date: '登録日(YYYY/MM/DD)', title: 'イベント名', start: '開始時刻(HH:MM)', end: '終了時刻(HH:MM)' }
  { date: '2026/06/30', title: 'TEST1', start: '09:20', end: '10:50' },
  { date: '2026/07/14', title: 'TEST2', start: '15:10', end: '16:40' },
];

// ▼ イベントの詳細文(不要な場合は空文字のまま)
const description = '';

// ▼ イベントの場所(不要な場合は空文字のまま)
const location = '';

// ────────────────────────────────────────────
// ラッパー関数(GAS エディタから直接実行用)
// ────────────────────────────────────────────
function 利用可能なカレンダーの一覧をログ出力() { __listCalendars(); }
function スケジュール登録()      { __registerEvents(false); }
function スケジュール登録_試行() { __registerEvents(true);  }
function スケジュール削除()      { __deleteEvents(false);   }
function スケジュール削除_試行() { __deleteEvents(true);    }

// ────────────────────────────────────────────
// メイン処理
// ────────────────────────────────────────────

/**
 * イベントを一括登録する実体
 * @param {boolean} dryRun - true の場合はログ出力のみ
 */
function __registerEvents(dryRun = false) {
  const CALENDAR_ID = __getCalendarTitleToID(CALENDAR_TITLE);
  const calendar = CalendarApp.getCalendarById(CALENDAR_ID);

  if (!calendar) {
    Logger.log('❌ カレンダーが見つかりませんでした。CALENDAR_ID を確認してください: ' + CALENDAR_ID);
    return;
  }

  Logger.log((dryRun ? '🧪 [DRY RUN] ' : '') + '📅 登録先カレンダー: ' + calendar.getName());

  events.forEach(function(ev) {
    const startTime = new Date(ev.date + ' ' + ev.start + ':00');
    const endTime   = new Date(ev.date + ' ' + ev.end   + ':00');

    if (!dryRun) {
      calendar.createEvent(ev.title, startTime, endTime, {
        description: description,
        location:    location,
      });
    }

    Logger.log(
      (dryRun ? '🧪 [DRY RUN] ' : '') +
      '登録' + (dryRun ? '予定' : '完了') + ': ' +
      ev.title + ' (' + ev.date + ' ' + ev.start + '〜' + ev.end + ')'
    );
  });

  Logger.log(
    (dryRun ? '🧪 [DRY RUN] ' : '✅ ') +
    '全 ' + events.length + ' 件の登録' +
    (dryRun ? '予定を確認しました(実際には登録されていません)' : 'が完了しました。')
  );
}

/**
 * イベントを一括削除する実体
 * events に定義された日付・タイトルが一致するイベントを検索して削除する
 * @param {boolean} dryRun - true の場合はログ出力のみ
 */
function __deleteEvents(dryRun = false) {
  const CALENDAR_ID = __getCalendarTitleToID(CALENDAR_TITLE);
  const calendar = CalendarApp.getCalendarById(CALENDAR_ID);

  if (!calendar) {
    Logger.log('❌ カレンダーが見つかりませんでした。CALENDAR_ID を確認してください: ' + CALENDAR_ID);
    return;
  }

  Logger.log((dryRun ? '🧪 [DRY RUN] ' : '') + '📅 削除対象カレンダー: ' + calendar.getName());

  let count = 0;

  events.forEach(function(ev) {
    const startTime = new Date(ev.date + ' 00:00:00');
    const endTime   = new Date(ev.date + ' 23:59:59');

    const dayEvents = calendar.getEvents(startTime, endTime);
    dayEvents.forEach(function(calEvent) {
      // タイトルが完全一致するイベントのみ削除対象になります
      if (calEvent.getTitle() === ev.title) {
        if (!dryRun) calEvent.deleteEvent();
        Logger.log(
          (dryRun ? '🧪 [DRY RUN] ' : '') +
          '削除' + (dryRun ? '予定' : '完了') + ': ' +
          ev.title + ' (' + ev.date + ')'
        );
        count++;
      }
    });
  });

  Logger.log(
    (dryRun ? '🧪 [DRY RUN] ' : '✅ ') +
    '全 ' + count + ' 件の削除' +
    (dryRun ? '予定を確認しました(実際には削除されていません)' : 'が完了しました。')
  );
}

// ────────────────────────────────────────────
// ユーティリティ
// ────────────────────────────────────────────

/**
 * 利用可能なカレンダーの一覧を _list 形式でログ出力する
 * 最初にこの関数を実行してカレンダー名と ID を確認してください
 */
function __listCalendars() {
  const calendars = CalendarApp.getAllCalendars();
  const lines = calendars.map(cal => `  "${cal.getName()}": "${cal.getId()}"`);
  Logger.log('const _list = {\n' + lines.join(',\n') + '\n}');
}

/**
 * カレンダー名からIDを取得する
 * @param {string} _title - カレンダー名
 * @returns {string} カレンダーID
 */
function __getCalendarTitleToID(_title) {
  const _id = _list[_title];
  if (!_id) {
    throw new Error('カレンダーが見つかりません: "' + _title + '" — _list に登録されているか確認してください。');
  }
  return _id;
}

実際に動かしてみる

events にこんなふうにイベントを書いておきます。

const events = [
  { date: '2026/06/30', title: '定例MTG', start: '10:00', end: '11:00' },
  { date: '2026/07/14', title: '定例MTG', start: '10:00', end: '11:00' },
];

ちなみに、このデータづくりが大変な時は AI を並走させるといい感じに作ってくれます。(地味に AI 併走を意識したデータ形式で作りました。)

まず スケジュール登録_試行 を実行すると、

🧪 [DRY RUN] 📅 登録先カレンダー: 仕事用
🧪 [DRY RUN] 登録予定: 定例MTG (2026/06/30 10:00〜11:00)
🧪 [DRY RUN] 登録予定: 定例MTG (2026/07/14 10:00〜11:00)
🧪 [DRY RUN] 全 2 件の登録予定を確認しました(実際には登録されていません)

ログにこう出ます。

問題なければ スケジュール登録 を実行。

📅 登録先カレンダー: 仕事用
登録完了: 定例MTG (2026/06/30 10:00〜11:00)
登録完了: 定例MTG (2026/07/14 10:00〜11:00)
✅ 全 2 件の登録が完了しました。

ログにこう出ます。

カレンダーを開くとちゃんと入ってる!まとめて登録できると地味にうれしい。

削除も同様で、スケジュール削除_試行 → スケジュール削除 の順で実行します。タイトルが完全一致するイベントだけ対象になるので、意図しないイベントを消してしまう心配が少ないのもポイントです。