見出し画像

複数組織に所属する人におすすめ!複数のGoogleカレンダーの予定を、内容を隠してお互いに同期する【GAS初心者用】

複数プロジェクト(案件)でPMをやっていると、案件によっては先方組織のメールアカウントでGoogleカレンダーに登録されます。
これまでは、ある案件でスケジュールが追加されたら別の組織のカレンダーの同じ時間帯に「予定あり」を入力して、自分のスケジュールをお知らせするようにしていました。

手動でカレンダー同期するのシンプルにめんどくさいのと(時間変更されるたびに別カレンダーの「予定あり」を手動で直す)まれに同時に同じ時間帯に大人数のMTGが入ったりすると、ダブルブッキングの調整というタスクが発生したりしていました。あと普通にスケジュール管理のヒューマンエラー多発。
こういうのこそDXするべきじゃね???と私の中のギャルが騒ぎ始めたので、GoogleカレンダーのGASをいじっていい感じにしてみたので共有します。

今回いくつかの参考サイトやブログを見ていったのですが、GASド初心者的には当たり前過ぎて省かれている単純な操作(どのボタン押したら保存なの?とか)でめちゃ時間かかったので、なるべくスクショ多めでGAS初めての人向けに書きたいと思っています。
ブラウザはGoogle chromeを使っています。

カレンダー間の連携の仕組みを考えよう

改善したい状況の整理(課題の整理)

現在3つのカレンダーを運用しています。

A→自分のカレンダー。ショットの案件のMTG、私用や作業予定など。
B→B社の会社アカウント。B社同僚が見ている&予定に招待される。
C→C社の会社アカウント。C社同僚が見ている&予定に招待される。

B社とC社はそれぞれNDA(秘密保持契約)があるので、予定の内容は共有したくない。
ゆえに、、B社でMTGに招待されたら→Aのカレンダーで同じ時間に「予定あり」を追加し、その予定にCのカレンダーを招待。ということを手動でコピー。ダブルブッキング連発し予定がカオスに。

こういう感じにしたい(理想の仕様)

  • Bのカレンダーに予定が入ったら、AとCに「●予定あり」としてコピーされる。他も同様に。

  • コピーされた予定もお互いにコピーし合うと無限に複製ループしてしまうので、「●予定あり」がタイトルの時はコピーしない。

コピーする予定のタイトル(ここでは「●予定あり」)は任意のタイトルでOKです。仕事用のカレンダーに入っていても不自然ではなく、絶対他の人が使わないようなタイトルにしてください。
これを3つのカレンダーで行う

1 :: Googleカレンダーの設定

Googleカレンダーの「…」メニュー
「設定と共有」を開く
「特定のユーザーとの共有」で
自分以外(これがAだったらBとC)のカレンダーを招待
権限を選択
「変更および共有の管理権限」を選択。会社のアカウントがGsuiteなどで権限が限られている場合はなるべく権限の広いものを選択。
送信すると、BとCのアカウント宛に共有の通知がいくので承認。

連携させるA、B、Cそれぞれの設定で、お互いにこの共有設定をしておきます。

2 :: スクリプトの調整

【コピペ用】ベースのスクリプトはこちら

▼Aのカレンダーの設定の場合

function uniteCal({
  //統合先のカレンダーID(会社のデフォルトカレンダーのIDを指定)
  var mainCal = CalendarApp.getCalendarById('AのカレンダーID');
  var startTime = new Date();

  //何日後まで同期するか
  var dayCount = 21;
  var endTime = new Date()
  endTime.setTime(startTime.getTime() + dayCount * 24 * 60 * 60 * 1000);

  //予定のタイトル
  var title = '●予定あり';

  //初期化:指定期間の間に「●予定あり」があったら削除
  var mainCalEvents = mainCal.getEvents(startTime, endTime);
  for(var i = 0; i < mainCalEvents.length; i++){
    var event = mainCalEvents[i];
    if(event.getTitle() == title){
      event.deleteEvent();
    } 
  }

  //統合元のカレンダーIDをリスト形式で列挙
  var subCalIds = ['BのカレンダーID''CのカレンダーID'];

  //B,Cのカレンダーを取得して、同時刻にAカレンダーに「●予定あり」イベントを作成
  for(var i = 0; i < subCalIds.length; i++){
    var subCal = CalendarApp.getCalendarById(subCalIds[i]);
    var subCalEvents = subCal.getEvents(startTime, endTime);
      for(var j = 0; j < subCalEvents.length; j++){
      var subCalEvent = subCalEvents[j];
      var status = subCalEvent.getMyStatus();
      // ●統合元のカレンダーから「予定ありがタイトルにある」または「欠席」はコピーしない
      if(subCalEvent.getTitle() != title && status != 'NO'){
        // allDayEvent(終日イベント)とそれ以外で条件分岐。
        if(subCalEvent.isAllDayEvent()){
          mainCal.createAllDayEvent(title, subCalEvent.getAllDayStartDate(), subCalEvent.getAllDayEndDate());
          Utilities.sleep(1000); 
        } else {
          mainCal.createEvent(title, subCalEvent.getStartTime(), subCalEvent.getEndTime());
          Utilities.sleep(1000); 
        }
      }
    }
  }
}

2-1 :: カレンダーのIDを入れる

「カレンダーの統合」の一番上にカレンダーIDが書いてあります(たぶんメールアドレス)

スクリプト3行目>AのカレンダーIDのところ

function uniteCal({
  //統合先のカレンダーID(会社のデフォルトカレンダーのIDを指定)
  var mainCal = CalendarApp.getCalendarById('AのカレンダーID');
  var startTime = new Date();

('xxxxx@gmail.com'); とかになります。シングルクォーテーションを消さないように。

スクリプト24行目>BのカレンダーID、CのカレンダーIDのところ

  //統合元のカレンダーIDをリスト形式で列挙
  var subCalIds = ['BのカレンダーID''CのカレンダーID'];

それぞれカレンダーIDを入れます。

2-2 :: 同期する期間を設定する

スクリプト7行目 var dayCount = 21;

  //何日後まで同期するか
  var dayCount = 21;
  var endTime = new Date()
  endTime.setTime(startTime.getTime() + dayCount * 24 * 60 * 60 * 1000);

これは今日から数えて21日後までの予定をクロールして同期する、という設定です。もっと短くしても長くしても良いのですが、ここでは同期の頻度と合わせてスクリプトの実行回数の制限を気にする必要があります。
(⚠最初設定した時、すぐに上限をオーバーしてスクリプトエラーで止まってしまったのでここの計算は重要です)

GAS(Google Apps Script)では、カレンダーの予定の追加を1日5000件までと制限しています。
私は1日に平均8件予定があるとして、1時間に1回は同期したいため

1日8件✕21日間分✕24回=4,032件 < 5000件以内

という計算で21日にしています。例えば「もっと予定が頻繁に変わるから15分に一度同期したい」場合は、1日の同期回数は96回となります。1日の予定件数と鑑みて同期する期間を調整してみてください。
※ただし、あまり直近の予定だけ同期されていてもカレンダーを共有している意味が無い気がするので最短14日間とかですかね…

2-3 :: コピーした後の予定のタイトルを決める

コピーされた予定は、B,Cのカレンダーにこんな感じで入ります

12行目のシングルクォーテーション''の間を書き換えてください。

  //予定のタイトル
  var title = '●予定あり';

私は自動処理する予定のタイトルに全角●を入れることで、万が一タイトルを公開できない予定が入った時の手動「予定あり」とかぶらないようにしました。(自動処理した予定は他のカレンダーにコピーしたくないため)

2-4 :: 欠席の予定はコピーしない

34行目

      // ●統合元のカレンダーから「予定ありがタイトルにある」または「欠席」はコピーしない
      if(subCalEvent.getTitle() != title && status != 'NO'){

大人数のMTGの一応招待されたけど(これ私出なくていいやつだな…)って時。Googleカレンダーの招待に対して「欠席」の返事をすると、他のカレンダーにコピーされず、その時間に別の予定を入れられるようにしました。
口頭で出席確認することもあるので、Googleカレンダーのステータスが「未定」(返事していない状態)はコピーされるようにしています。
もし、欠席も含めて他カレンダーに「●予定あり」として反映したい場合は

      // ●統合元のカレンダーから「予定ありがタイトルにある」または「欠席」はコピーしない
      if(subCalEvent.getTitle() != title){

「 && status != 'NO'」を消してください。←ここで欠席はコピーしない、の指示をしている。

3 :: GASにプロジェクトを追加する

3-1 :: Google Apps Scriptを開く

Googleアカウントにログインした状態で、こちらのURLをクリック。

https://script.google.com/home

3-2 :: 新規プロジェクトを追加

入るとこんな画面。「新しいプロジェクトを追加」をクリック
入ってるスクリプトを全部消して、さっき作ったやつをコピペ
プロジェクトタイトルを付けておきましょう
「カレンダー同期」のプロジェクト名にしました
フロッピーマーク(!)で保存

5 :: GASでトリガーを設定する

トリガーとは「何きっかけでそのスクリプトを発動する?」という発動条件を設定するものです。

トリガーをクリック
右下の「トリガーを追加」をクリック
2-2で計算した通り、同期の頻度を設定します
「時間ベースのタイマー」を「分ベース」にすると、15分おき等も設定できます
保存をクリック
すると、Googleアカウントとの連携を求められます。パスワードを入れる
アラートが出てきますが大丈夫!左の「Hide Advanced」をクリック
「Go to カレンダー同期(unsafe)」をクリック(unsafeじゃないので大丈夫)
「Allow」(許可する)をクリック

6 :: 実行してみる

エディタに戻る
「実行」をクリック

これで、AのカレンダーにBとCの予定の同じ時間帯に「●予定あり」が追加されていけば成功です。
※今の時間以前の予定は同期されないため、検証には未来の予定をいくつか入れておく必要があります。

以降はトリガーが設定してあるので1時間おき(指定した頻度)で自動的に同期してくれます。

🎉 完成 🎉

「AのカレンダーにBとCの予定を同期」が以上で完了しました!!🎉
同じ操作をBのカレンダー、Cのカレンダーにも行ってください(スクリプト内のメールアドレスの入れ替えを忘れずに)

参考にした記事&教えてもらった人

同じくフリーランスで複数組織に所属している稲田さん(17design.)にアイデアをいただき、フロントエンドもできるデザイナー菅野さん(minm)にQiitaからのアレンジをいろいろ教えてもらいました!

私はこれが完成してから予定の調整に脳のリソースを使わなくて良くなり、まじで日常の1つタスクが消えた感じで晴れ晴れしています。
是非お試しを。

★このnote用に操作画面のスクショを撮ったツール tango.us

chrome拡張を入れてブラウザで操作していくだけで、押したところをハイライトした状態でステップごとのスクショを撮ってくれます。
今回はnote貼り付け用に画像をDLしてしまいましたが、そのまま共有リンクにできるみたい。これも神ツール。

この記事が気に入ったらサポートをしてみませんか?