【GAS】複数のGoogleカレンダーの予定をまとめてスプレッドシートに書き出す

## はじめに
発売スケジュール等複数あるカレンダーの予定を見て、指定期間内の日付とイベント名を全て書き出したいという依頼を受けました。
いままでは手作業でコピー＆ペーストしていたそうなので（大変）、これを自動でできるようにします。

## カレンダーIDのリストを作成
スプレッドシートに、「カレンダー名」「カレンダーID」のリストを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311544/7770a16c-ae52-e26d-cd8f-126535d4c125.png)
このシートから設定を読み出していくようになります。

## カスタムメニュー作成
今回はカスタムメニューから期間指定ダイアログを出し、その内容で出力するようにしたいと思います。
まずはダイアログ画面のhtmlを下記の様に作りました。
クリックするとexportEventが呼ばれるようになっています。
また連打防止のためにsubmitボタンをdisableにし、結果が出力されたらダイアログを閉じるようにしています。
```html:dialog.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <form>
      取得期間：
      <input type="date" name="startTime"> ～ 
      <input type="date" name="endTime"><br/><br />
      <input type="button" value="シート作成" onClick="exportEvent(this.parentNode)" name="submit" />
    </form>
    <script>
      function exportEvent(form) {
        form.submit.disabled = true;
        google.script.run.withSuccessHandler(function(){
          google.script.host.close();
        }).exportEvents(form.startTime.value,form.endTime.value);
      }
    </script>
  </body>
</html>
```

## シートへの出力処理
シートに出力されるコードは下記となります。
```javascript:main.gs
var CALENDAR_LIST_ID = "カレンダーIDが記載されているスプレッドシートのID";
var CALENDAR_LIST_SHEET_NAME = "カレンダーIDが記載されているシート名";

var _spreadSheetSettings = {};


//======================================================================================================
// スプレッドシートを開いたときのトリガーで呼ばれるメソッド
//======================================================================================================
function onOpen() {

  var customMenu = SpreadsheetApp.getUi()
  customMenu.createMenu('カスタム')　//メニューバーに表示するカスタムメニュー名

      .addItem('スケジュールエクスポート', 'openDialog')　//メニューアイテムを追加
      .addToUi()

}

//======================================================================================================
// ダイアログを開く
//======================================================================================================
function openDialog(){
  var html = HtmlService.createHtmlOutputFromFile('dialog').setHeight(100);
  SpreadsheetApp.getUi().showModalDialog(html, "エクスポート期間指定");
}

//======================================================================================================
// 毎回スプレッドシートを開かなくていいように使いまわす
//======================================================================================================
function getSheet(ssId,wsName){

  if(ssId in _spreadSheetSettings){
    if(!(wsName in _spreadSheetSettings[ssId]["ws"])){
      _spreadSheetSettings[ssId]["ws"][wsName] = _spreadSheetSettings[ssId]["ss"].getSheetByName(wsName);      
    }
  }else{
    _spreadSheetSettings[ssId] = {"ss":SpreadsheetApp.openById(ssId),"ws":{}}
    _spreadSheetSettings[ssId]["ws"][wsName] = _spreadSheetSettings[ssId]["ss"].getSheetByName(wsName);
  }

  if(!_spreadSheetSettings[ssId]["ws"][wsName]){
    _spreadSheetSettings[ssId]["ws"][wsName] = _spreadSheetSettings[ssId]["ss"].insertSheet(wsName);
  }

  return _spreadSheetSettings[ssId]["ws"][wsName];
}


//======================================================================================================
// 新規にシートを作成してイベントの日付＆タイトルを書き出していく
//======================================================================================================
function exportEvents(since,until){
  var events = getEvents(since,until);
  var sheetName = since + "～" + until;
  var sheet = getSheet(CALENDAR_LIST_ID,sheetName);

  if(sheet){
    var values = [];
    events.forEach(function(event){
      values.push([Utilities.formatDate(event.date, "Asia/Tokyo", "yyyy/MM/dd"),event.category,event.title]);
    });
    sheet.getRange(1,1,values.length,3).setValues(values);
  }
}


//======================================================================================================
// カレンダー一覧から指定期間のイベントを取得
//======================================================================================================
function getEvents(since,until){
  var calendarList = getCalendarIdList();
  var eventList = [];

  var startTime = new Date(since);
  startTime.setHours(0,0,0);
  var endTime = new Date(until);
  endTime.setHours(23,59,59);

  calendarList.forEach(function(calendar){
    CalendarApp.subscribeToCalendar(calendar.id);
    calendarObj = CalendarApp.getCalendarById(calendar.id);

    var events = calendarObj.getEvents(startTime,endTime);

    events.forEach(function(event){
      var title = event.getTitle();
      var date = event.getStartTime();
        if(date >= startTime){
        eventList.push({
          "category":calendar.name,
          "title":title,
          "date":date
        })
        Logger.log(date + ":" + title);
      }

    });

  });

  // 昇順
  eventList.sort(function(a, b) {
    return a.date - b.date;
  });

  return eventList;


}

//======================================================================================================
// スプレッドシートからカレンダーIDのリストを取得
//======================================================================================================
function getCalendarIdList(){
  var ws = getSheet(CALENDAR_LIST_ID,CALENDAR_LIST_SHEET_NAME);
  var values = ws.getRange(2,1,ws.getLastRow()-1,2).getValues();
  var idList = [];
  values.forEach(function(value){
    idList.push({
      "name":value[0],
      "id":value[1],
    })
  });
  return idList;
}

```

上記の設定をすると、スプレッドシートに「カスタム」というメニューが追加され、そこから「スケジュールエクスポート」を選ぶことで下記のダイアログが出るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311544/aba3b972-f5a1-6b2d-eb58-b43ec481db98.png)

## おわりに
処理内容自体は特段大したことはないのですが、実はこういった「手作業だと大変だけど自動化すると一瞬」といった事務作業は沢山あるので、どんどん快適にしていきたいですね。