0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GAS】複数のGoogleカレンダーの予定を一覧で把握したい!

Last updated at Posted at 2025-01-26

はじめに

仕事で使ってるGoogleカレンダーをチームで管理して、カレンダー表示+一覧化してほしいとのことで、今回やったことの備忘録を残します。

そのため今回はスプレッドシートに予定を出力するまでとなります。

準備するもの

  • Googleアカウント
  • Googleスプレッドシート
  • GASエディタ
  • Googleカレンダー

簡単な流れ

  1. Googleカレンダーで設定変更
    1. 各ユーザーのカレンダーIDを取得
    2. Googleカレンダーで他のユーザーの閲覧を許可
  2. スクリプトを書いていく
  3. 挙動確認

実際にやってみた

今回はユーザー①のカレンダーにユーザー②の予定を追加して、ユーザー①のスプレッドシートで予定を管理していきます。

  1. Googleカレンダーでの設定

    1. カレンダーIDを取得(人数分)
      1. Googleカレンダーを開く
      2. 右上の歯車マーク→「設定」を押下
      3. 左下のマイカレンダーの設定の設定したいユーザー→「カレンダーの統合」を押下
      4. 「カレンダーID」と記載されているものがIDです。後ほど使いますので、控えておいてください
    2. 他のユーザーの閲覧を許可する
      1. 招待する側(ユーザー②)のGoogleカレンダーを表示する

      2. 上記3で開いたようにマイカレンダーの設定の「予定のアクセス権限」を押下

      3. 「特定のユーザーまたはグループと共有する」欄の「ユーザーやグループを追加」と記載されているプラスボタンを押下

      4. 共有したいユーザー(ユーザー①)のメールアドレスを入力

        今回は予定を参照できればOKなので、権限は「予定の表示(すべての予定の詳細)」にしますが、必要最低限の権限にすることをお勧めします。

      5. 招待されたユーザー(ユーザー①)のGmailを開き、招待メールを確認

      6. メール内の「このカレンダーを追加」を押下

      7. 自動でGoogleカレンダーに移動して、「カレンダーを追加」とポップアップが出るので、「追加」を押下

  2. GASを書いていく

    2025/02/01に追記しています。完成系のコードはこちらへ
    完成したコードはこちら

    function getCalender() {
      // 上記で指定したidを指定
      const idA = 'カレンダーID①';
      const idB = 'カレンダーID②';
      const user = [idA, idB]; // idを配列に格納
      var eventDetails = []; // 配列を用意
      // 各ユーザーの予定を取得(二次元配列)
      for (let i=0; i<user.length; i++) {
        eventDetails[i] = getSchedule(user[i]); 
      }
      eventDetails = eventDetails.flat(); // 配列を平坦化
      eventDetails = sort(eventDetails); // 予定を開始時刻で昇順
      write(eventDetails); // スプレッドシートに記入
    }
    
    function getSchedule(id) {
      const calendar = CalendarApp.getCalendarById(id); // 指定したIDのカレンダーを取得
      const events = calendar.getEventsForDay(new Date()); // 今日のイベントを取得(取得したい日時によって修正してください)
      var result = []; // 配列を用意
      const keys = ['title', 'user', 'startTime', 'endTime'];
    
      for (let i=0; i<events.length; i++) {
        var event = events[i];
        // 各項目を変数に代入
        var title = event.getTitle(); // タイトルを取得
        var email = event.getCreators().toString(); // メールアドレスを取得
        var startTime = changeDateFormat(event.getStartTime()); // 開始時刻を日本時間表記に変換
        var endTime = changeDateFormat(event.getEndTime()); // 終了時刻を日本時間表記に変換
        var values = [title, email, startTime, endTime];
        
        var obj = {};
        for (let j=0; j<keys.length; j++) {
          obj[keys[j]] = values[j];
        }
        result.push(obj);
      }
      return result;
    }
    
    function changeDateFormat(date) {
      var newDate = Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm:ss');
      return newDate;
    }
    
    function sort(eventDetails) {
      eventDetails.sort((a, b) => new Date(a.startTime) - new Date(b.startTime));
      return eventDetails;
    }
    
    function write(eventDetails) {
      // シートを指定して取得
      const ss = SpreadsheetApp.getActiveSpreadsheet();
      const sheet = ss.getSheetByName('シート1'); // ここはシート名に合わせて修正してください
      sheet.clear(); // シートをリセット
      const headers = ['予定', 'メールアドレス', '開始時刻', '終了時刻'];
      sheet.appendRow(headers); // ヘッダーを入力
      // 取得したデータを入力
      for (let i=0; i<eventDetails.length; i++) {
        sheet.getRange('A'+(i+2)).setValue(eventDetails[i].title);
        sheet.getRange('B'+(i+2)).setValue(eventDetails[i].user);
        sheet.getRange('C'+(i+2)).setValue(eventDetails[i].startTime);
        sheet.getRange('D'+(i+2)).setValue(eventDetails[i].endTime);
      }
    }
    
    
  3. 挙動確認

    1. GASエディタの「実行ボタン」を押下
    2. 初回は「認証が必要です」みたいなポップアップが表示されるので、「続行」→アカウントを選択→「詳細」→「安全ではないページに移動」→「許可」と押下していく
    3. 再度「実行」ボタンを押下
    4. スプレッドシートに戻って、予定が表示されればOK

今後のアイディア

  • トリガー設定をしてこの処理をバッチ化、取得した予定をLINEやGmail、Slackなどに毎朝送るようにすればスプレッドシートを開かずに1日の予定を確認できる
  • ↑をやるならその日に入った予定の扱いをどうするか。。そこまで気にしないか、予定が入ったらリアルタイムで知らせるとか。

まとめ

今回はGoogleカレンダーでしたが、そのほかのカレンダーアプリ(TimeTreeとか)との連携とかも今度やってみたいと思います。
こうした方がシンプルにできる、ここがわかりづらい等ありましたらコメントください!
よければいいねもお願いします!

2025/02/01追記

  1. ID取得を柔軟に対応できるようにしゅうせ
    上記のコードではユーザの追加、削除等に対応しにくいと思いますので、少しメソッドを追加していきます。
    作戦としては指定したシートにID、メールアドレス、ユーザ名を入力して、それを取得するメソッドを追加します。
    1. ユーザ情報シートを作成
    2. 以下メソッドを追加、その他コードを修正
      • 追加メソッド
        function getUserList() {
          // シートを指定して取得
          const ss = SpreadsheetApp.getActiveSpreadsheet();
          const sheet = ss.getSheetByName('ユーザ情報');
          
          var lastRow = sheet.getLastRow(); // 情報が入力されている最終行を取得
          var range = sheet.getRange(2,1,lastRow - 1,3); // A2:C列最終行まで取得
          var userList = range.getValues();
        
          return userList;
        }
        
      • 修正メソッド
        function getCalender() {
        -   // 上記で指定したidを指定
        -    const idA = 'カレンダーID①';
        -    const idB = 'カレンダーID②';
        -    const user = [idA, idB]; // idを配列に格納
        -    var eventDetails = []; // 配列を用意
        +    // idを取得
        +    var userList = getUserList();
        +    var idList = []; // 配列を用意
        +    for (let i = 0; i < userList.length; i++) {
        +      idList[i] = userList[i][0] // idを配列に格納
        +    }
        
          var eventDetails = []; // 配列を用意
          // 各ユーザーの予定を取得(二次元配列)
        -    for (let i=0; i<user.length; i++) {
        -      eventDetails[i] = getSchedule(user[i]); 
        -    }
        +    for (var i = 0; i < idList.length; i++) {
        +      eventDetails[i] = getSchedule(idList[i]); 
        +    }
        
          eventDetails = eventDetails.flat(); // 配列を平坦化
          eventDetails = sort(eventDetails); // 予定を開始時刻で昇順
          write(eventDetails); // スプレッドシートに記入
        }
        
  2. メールアドレス→ユーザ名に変換
    以前はメールアドレスを表示していましたが、(次の記事では)LINEに送信となるとメッセージの中にメールアドレスがあると見づらいなと。。
    そのためメールアドレスからユーザー名に変換する処理を追加します。
    といっても上記で追加したメソッドを流用します。
    1. 修正したコード
          function getSchedule(id) {
            const calendar = CalendarApp.getCalendarById(id); // 指定したIDのカレンダーを取得
            const events = calendar.getEventsForDay(new Date()); // 今日のイベントを取得(取得したい日時によって修正してください)
            var result = []; // 配列を用意
            const keys = ['title', 'user', 'startTime', 'endTime'];
          
            for (let i=0; i<events.length; i++) {
              var event = events[i];
              // 各項目を変数に代入
              var title = event.getTitle(); // タイトルを取得
              var email = event.getCreators().toString(); // メールアドレスを取得
              var startTime = changeDateFormat(event.getStartTime()); // 開始時刻を日本時間表記に変換
              var endTime = changeDateFormat(event.getEndTime()); // 終了時刻を日本時間表記に変換
      +        // 「ユーザ情報」からメールアドレスとユーザ名を取得
      +         var userList = getUserList();
      +         // メールアドレスをユーザ名に変換
      +         var user = '';
      +         for (let i = 0; i < userList.length; i++) {
      +           if (userList[i][1] == email) {
      +             user = userList[i][2];
      +           }
      +         }
      
      -        var values = [title, email, startTime, endTime];
      +        var values = [title, user, startTime, endTime];
              
              var obj = {};
              for (let j=0; j<keys.length; j++) {
                obj[keys[j]] = values[j];
              }
              result.push(obj);
            }
            return result;
          }
      

完成したコードの全容

function getCalender() {
  // メールアドレスを取得
  var userList = getUserList();
  var idList = []; // 配列を用意
  for (let i = 0; i < userList.length; i++) {
    idList[i] = userList[i][0] // idを配列に格納
  }

  var eventDetails = []; // 配列を用意
  // 各ユーザーの予定を取得(二次元配列)
  for (var i = 0; i < idList.length; i++) {
    eventDetails[i] = getSchedule(idList[i]); 
  }

  eventDetails = eventDetails.flat(); // 配列を平坦化
  eventDetails = sort(eventDetails); // 予定を開始時刻で昇順
  write(eventDetails); // スプレッドシートに記入
}

function getSchedule(id) {
  var calendar = CalendarApp.getCalendarById(id); // 指定したIDのカレンダーを取得
  var events = calendar.getEventsForDay(new Date()); // 今日のイベントを取得
  var result = [];
  var keys = ['title', 'user', 'startTime', 'endTime'];

  for (var i = 0; i < events.length; i++) {
    var event = events[i];
    var title = event.getTitle(); // タイトルを取得
    var email = event.getCreators().toString(); // メールアドレスを取得
    var startTime = changeDate(event.getStartTime()); // 開始時刻を日本時間表記に変換
    var endTime = changeDate(event.getEndTime()); // 終了時刻を日本時間表記に変換

    // 「ユーザ情報」からメールアドレスとユーザ名を取得
    var userList = getUserList();
    // メールアドレスをユーザ名に変換
    var user = '';
    for (let i = 0; i < userList.length; i++) {
      if (userList[i][1] == email) {
        user = userList[i][2];
      }
    }
    
    var values = [title, user, startTime, endTime];
    var obj = {};

    for (var j = 0; j < keys.length; j++) {
      obj[keys[j]] = values[j];
    }
    result.push(obj);
  }
  return result;
}

function changeDate(date) {
  const newDate = Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm:ss');
  return newDate;
}

function sort(eventDetails) {
  eventDetails.sort((a, b) => new Date(a.startTime) - new Date(b.startTime));
  return eventDetails;
}

function write(eventDetails) {
  // シートを指定して取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('シート1');
  sheet.clear(); // シートをリセット
  const headers = ['予定', 'ユーザー', '開始時刻', '終了時刻'];
  sheet.appendRow(headers); // ヘッダーを入力

  // 取得したデータを入力
  for (var i = 0; i < eventDetails.length; i++) {
    sheet.getRange('A'+(i+2)).setValue(eventDetails[i].title);
    sheet.getRange('B'+(i+2)).setValue(eventDetails[i].user);
    sheet.getRange('C'+(i+2)).setValue(eventDetails[i].startTime);
    sheet.getRange('D'+(i+2)).setValue(eventDetails[i].endTime);
  }
}

function getUserList() {
  // シートを指定して取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('ユーザ情報');
  
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange(2,1,lastRow - 1,3);
  var userList = range.getValues();

  return userList;
}

追記したせいで、だいぶ記事が長くなってしまった。。すみません。。

参考文献

以下のサイトを参考にさせていただきました。ありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?