Google Apps Scriptを使ってカレンダーの同期

# Google Apps Scriptを使ってカレンダーの同期

仕事で2つのGoogleアカウントを使っていて、2つのIDのGoogleカレンダーの内容を同期したい、という（個人的）ニーズがあったため、Google Apps Scriptを使って実現しました。

同期というのは、片方のIDのカレンダーの中に、もう一方のIDが参加者に入っていないスケジュールがあった場合に、参加者にもう一方のIDを追加する、というようにしています。

## Google Apps Scriptを使うための準備

入門記事はいろいろあるのでここでは簡単に書きます。
（画面キャプチャとかあるような親切な記事がよい方は、この部分は他の記事を参考に。。）

- Googleドライブの「新規」→「その他」→「アプリを追加」から「Google Apps Script」を追加
- これで、「新規」→「その他」から「Google Apps Script」のプロジェクトを新規に作成できるようになります


## スクリプトの作成

- Googleドライブの「新規」→「その他」から「Google Apps Script」を選択します。
- プロジェクト名が「無題のプロジェクト」となっているので、適当な名前を設定（例：sync_calendar）
- 「コード.gs」の内容を、以下の内容にします。

```js

var myId = 'xxx@gmail.com';     // 同期元のカレンダーのID
var targetId = 'yyy@gmail.com'; // 同期先のカレンダーのID
var dateRange = 30;  // 同期する期間（30なら今日から30日分）
var logMailTo = 'xxx@gmail.com';  // 同期が発生したときのメール通知先
var logMailSubject = 'スケジュール同期通知';   // 同期が発生したときのメール件名

function myFunction() {
  var myCal =  CalendarApp.getCalendarById(myId); // 同期元のカレンダーの取得
  var today = new Date(); // 今日の日付の取得
  var logMail = '';
  
  for(var i=0; i<dateRange; i++) {
    var date = new Date();
    date.setDate(today.getDate() + i); // 日付を1日ずつずらす
    Logger.log('[' + toDateString(date) + ']');
    
    var myEvents = myCal.getEventsForDay(date);
    
    for(var j=0; j<myEvents.length; j++){
      var title = myEvents[j].getTitle();
    
      if (isTargetIdJoined(myEvents[j])) {
        Logger.log(title + ': joined');
      } else {
        Logger.log(title + ': not joined');
        myEvents[j].addGuest(targetId);
        logMail += toDateTimeString(myEvents[j].getStartTime()) + '-' + 
          toDateTimeString(myEvents[j].getEndTime()) + ': ' + title + "\n";
      }
    }
  }
    
  if (logMail != '') {
    var body = "以下のスケジュールを" + targetId + "に連携しました。\n\n" + logMail;
    MailApp.sendEmail(logMailTo, logMailSubject, body);
    Logger.log(body);
  }
}

// スケジュール（Event）に同期先のカレンダーのIDがすでに入っているか
function isTargetIdJoined(event) {
  var guest = event.getGuestByEmail(targetId);
  if (guest) {
    return true;
  } else {
    return false;
  }
}

// Dateを日付文字列に変換
function toDateString(date) {
  return date.getYear() + '/' + (date.getMonth()+1) + '/' + date.getDate();
}

// Dateを日付＋時間（時と分まで）に変換
function toDateTimeString(date) {
  var minutes = '';
  if (date.getMinutes() < 10) {
    minutes = '0' + date.getMinutes();
  } else {
    minutes = date.getMinutes();
  }
  
  return date.getYear() + '/' + (date.getMonth()+1) + '/' + date.getDate() + ' ' +
    date.getHours() + ':' + minutes;
}
```

- 以下の3つの値は、ご自身のID（メールアドレス）を設定してください。

```js

var myId = 'xxx@gmail.com';     // 同期元のカレンダーのID
var targetId = 'yyy@gmail.com'; // 同期先のカレンダーのID
var logMailTo = 'xxx@gmail.com';  // 同期が発生したときのメール通知先
```

- 以下の2つの値は、任意で変更してください。

```js

var logMailSubject = 'スケジュール同期通知';   // 同期が発生したときのメール件名
var dateRange = 30;  // 同期する期間（30なら今日から30日分）
```


## スクリプトの実行

- 最初の実行では、dateRangeの値を1とか小さい値にして、問題なく動作することを確認してから大きい値にすることをお勧めします。
- スクリプトを実行する前に、同期元のカレンダーのIDから同期先のカレンダーのIDの参照権限がない場合は、権限を追加してください。
- 「実行」メニューから、「関数を実行」→「myFunction」を選択すると手動でスクリプトを実行できます。（右向き三角形の実行ボタンでも可）
- 初回の実行では、スクリプトへの権限付与（カレンダー、メールに関する操作）を促すダイアログが出るので、権限を付与してください。


## 自動実行の設定

スクリプトを自動で定期的に実行したい場合の手順です。
ここでは、1時間ごとに定期実行するように設定しています。

- 「編集」メニューから、「現在のプロジェクトのトリガー」を選択
- 右下の「トリガーを追加」を選択
- 以下のように設定して「保存」を選択
    -  実行する関数：myFunction
    -  実行するデプロイ：Head
    -  イベントのソース：時間主導型
    -  時間ベースのトリガーのタイプ：時間ベースのタイマー
    -  時間の間隔：1時間おき

これで、1時間ごとに自動事項されるようになります。