ども!久しぶりに金曜日もお家で、ブログを執筆している龍ちゃんです。突然ですが、Google Calendar使っていますか?僕は入社してから、いろいろな予定をGoogle Calendarで管理するようになりました。ほぼ、TODOリスト化しています。手動で管理するのもいいんですが、システム化できそうと思っちゃったので検証したのでその報告になります。
今回は、Google Apps Script(GAS)を使ってGoogle Calendarに予定の登録・取得についてまとめました。ドキュメントは充実していましたが、例がなんとも言えない感じだったのでGoogle Calendarヘビーユーザーの皆さんに代わってソースコードを用意したので、コピペして動かしながら試してください。
事前準備
検証を進めていくにあたっての準備なので、ソースを知りたい方は読み飛ばしていただいて大丈夫です。
新しいGoogle Calendarを用意する
うっかり、「メインのカレンダーの予定を消してしまった!」なんてことにならないように、検証用の新しいカレンダーを用意しておきましょう。https://calendar.google.com/にアクセスして、新しいカレンダーを作成しましょう。
今回は「GAS API Test」という名前のカレンダーを用意しました。次に、カレンダーの設定に入り「カレンダーの統合>カレンダーID
」というIDを控えてください。
こちらのIDを用いてカレンダーにアクセスするので、この手順を覚えておきましょう。
共通設定:GASでGoogle Calndarにアクセス準備
まずは、GASエディタ上でGoogle Calndar APIへのサービス追加を行います。こちらを設定することでサジェスチョン機能が有効になります。
次に、カレンダーへのアクセス処理をグローバル変数として設置します。カレンダーへの参照はすべてのコードの前段として必要になります。先ほど事前準備で取得したカレンダーID
を以下のxxxxx
部分に変更してください。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// カレンダーへの参照
const calendar = CalendarApp.getCalendarById(calenarID)
JSのDate型で日付と時間を指定する
今回の内容で取り扱う、Date型セットを用意しました。
// 実行したタイミングの日付情報を取得する
const date = new Date()
Logger.log(date)
// 年:月:日をそれぞれ取得する
// 月も日も0からカウントされるため、実世界と合わせるためには+1する
Logger.log(`${date.getFullYear()}:${date.getMonth()+1}:${date.getDate()+1}`)
// 西暦で設定する
date.setFullYear(2024)
Logger.log(date)
// 次の月に設定
date.setMonth(date.getMonth()+1)
Logger.log(date)
// 次の日に設定
date.setDate(date.getDate()+1)
Logger.log(date)
// 時間情報をセットする
// 0時12分00秒
date.setHours(00, 12, 00)
Logger.log(date)
取得:年・月・日
const date = new Date()
Logger.log(date)
// 年:月:日をそれぞれ取得する
Logger.log(`${date.getFullYear()}:${date.getMonth()+1}:${date.getDate()}`)
月に関しては、0
からカウントがスタートします。そのため、現実と合わせるためには月は+1
させることで現実と即した値になります。
情報設定(日付):setFullYear
/setMonth
/setDate
const date = new Date()
Logger.log(date)
// 西暦で設定する
date.setFullYear(2024)
Logger.log(date)
// 次の月に設定
date.setMonth(date.getMonth()+1)
Logger.log(date)
// 次の日に設定
date.setDate(date.getDate()+1)
Logger.log(date)
月は情報は、0
からカウントがスタートします。月情報が12月を超えて設定した場合は、年が+1
されます。日付情報が有効な日付の場合は設定され、超えた場合は月が+1
されます。
情報設定(時間情報):setHours
const date = new Date()
Logger.log(date)
// 時間情報をセットする
// .setHours(hours, min, sec)
date.setHours(00, 12, 00)
Logger.log(date)
時間情報設定するsetHours
の引数は3つあります。
パラメータ | 説明 |
---|---|
hours | 時間を設定する(0~23):24以降では日付がプラスされる |
min | 分を設定する(0~59) |
sec | 秒を設定する(0~59) |
こちらの設定方法は、現実と即した形で設定することができます
GASでGoogle Calendarを操作する
よく使用する登録・取得の方法についてまとめていきます。コマンドの種類が豊富なので、用途別にまとめて行きます。公式リファレンスでオブジェクトの説明があるので開きながら見てもらえると良いですね。
説明 | URL |
---|---|
Google Calendarで扱えるオブジェクト | https://developers.google.com/apps-script/reference/calendar/calendar?hl=ja |
Eventオブジェクト | https://developers.google.com/apps-script/reference/calendar/calendar-event?hl=ja |
こちらで、カレンダーオブジェクトの取得が完了します。
単一の予定を追加する:createEvent
ドキュメントとしては、こちらになります。サンプルでは、実行した当日のカレンダーに対して、15:00~16:00の一時間で予定が追加されます。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const setEvent = () => {
const startTime = new Date()
startTime.setHours(15, 0, 0)
const endTime = new Date()
endTime.setHours(16, 0, 0)
const options = {
// description: "説明",
// location:"自宅",
// <guests:"example1@example.com>, example2@example.com",
// sendInvites:false
}
const event = calendar.createEvent("title", startTime, endTime, options)
}
createEvents
の引数は、4つです。それぞれ、以下を設定することができます。
名前 | 型 | 説明 |
---|---|---|
title | String | イベントのタイトル:必須 |
startTime | Date | イベントの開始日時:必須 |
endTime | Date | イベントの終了日時:必須 |
options | Object | イベントの詳細設定:オプション |
options
は名前の通り、設定しなくても動作します。optionsで設定できる値としては、以下のようになります。
名前 | 型 | 説明 |
---|---|---|
description | String | イベントの説明 |
location | String | イベントの場所 |
guests | String | ゲストとして追加するメールアドレス(複数人の場合はカンマ区切り) |
sendInvites | boolean | 招待メールを送信するか(デフォルト:false) |
コメントアウトを外して実行すると、optionsで指定した内容のカレンダー予定が登録されます。
終日のイベントを追加する:createAllDayEvent
ドキュメントとしては、こちらになります。サンプルでは、終日(一日)・終日(二日)・終日(二日:詳細付き)の予定が3つ登録されます。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const setAllDayEvent = () => {
const startTime = new Date()
calendar.createAllDayEvent("test", startTime)
// 終了日は含まれないため(予定を入れたい日+1)指定
const endTime = new Date()
endTime.setDate(endTime.getDate() + 2)
calendar.createAllDayEvent("test", startTime, endTime)
const options = {
description: "説明",
location: "自宅",
guests: "example1@example.com, example2@example.com",
sendInvites: false
}
calendar.createAllDayEvent("test", startTime, endTime, options)
}
createAllDayEvent
の引数は、4つです。
名前 | 型 | 説明 |
---|---|---|
title | String | イベントのタイトル:必須 |
startTime | Date | イベントの開始日時(日付のみが参照される):必須 |
endTime | Date | イベントの終了日時(日付のみが参照され、終了日は範囲に含まれない):オプション |
options | Object | イベントの詳細設定:オプション |
optionsで設定することができる値は、以下になります。
名前 | 型 | 説明 |
---|---|---|
description | String | イベントの説明 |
location | String | イベントの場所 |
guests | String | ゲストとして追加するメールアドレス(複数人の場合はカンマ区切り) |
sendInvites | boolean | 招待メールを送信するか(デフォルト:false) |
createAllDayEvent
で気を付けたい点としては、endTime
を設定する場合です。終了日は含まれません。設定したい期間通りに設定できているかを注意深く確認する必要があります。
繰り返し単一の予定を追加する:createEventSeries
それぞれ、単一・終日の登録を見てきました。それぞれのイベント形態を繰り返し登録することができる関数がcreateEventSeries
・createAllDayEventSeries
です。こちらのサンプルはcreateEventSeries
です。サンプルでは、「一か月間、水曜日と木曜日の15:00~16:00に予定」が登録されます。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const setSeriesEvent = () => {
const startTime = new Date()
startTime.setHours(15, 0, 0)
const endTime = new Date()
endTime.setHours(16, 0, 0)
const endScedule = new Date()
endScedule.setMonth(endScedule.getMonth() + 1)
const recurrence = CalendarApp.newRecurrence()
.addWeeklyRule()
.onlyOnWeekdays([CalendarApp.Weekday.THURSDAY, CalendarApp.Weekday.TUESDAY])
.until(endScedule)
const options = {
description: "説明",
location:"自宅",
guests:"example1@example.com, example2@example.com",
sendInvites:false
}
calendar.createEventSeries("title", startTime, endTime, recurrence, options)
}
createEventSeries
で登録することができる引数は5つです。
名前 | 型 | 説明 |
---|---|---|
title | String | イベントのタイトル:必須 |
startTime | Date | イベントの開始日時(最初のイベント):必須 |
endTime | Date | イベントの終了日時(最初のイベント):必須 |
recurrence | EventRecurrence | 繰り返しのルール:必須 |
options | Object | イベントの詳細設定:オプション |
optionsの設定する値は、createEvent
と共通です。この関数で重要になるのはrecurrence
の設定項目です。指定することができるパラメーターとしては、こちらにまとまっています。
繰り返し終了条件を決定する方法として、繰り返し回数(.times(number)
)と期間(.until(Date)
)があります。これらを使用用途によって使い分けてください。
以下に汎用性が高い、繰り返しルールを記載しておきます。
特定曜日のみ繰り返すサンプル
ホワイトリスト方式とブラックリスト方式のそれぞれの方式で記載します。
// 記載されている曜日を削除することで機能する:ホワイトリスト方式
// 週単位で、特定の曜日のみ繰り返す
const sceduleRule = CalendarApp.newRecurrence()
.addWeeklyRule()
.onlyOnWeekdays([
CalendarApp.Weekday.SUNDAY,
CalendarApp.Weekday.MONDAY,
CalendarApp.Weekday.TUESDAY,
CalendarApp.Weekday.WEDNESDAY,
CalendarApp.Weekday.THURSDAY,
CalendarApp.Weekday.FRIDAY,
CalendarApp.Weekday.SATURDAY
]).times(10)
// 除外したい曜日を記載することで機能する:ブラックリスト方式
// 毎日繰り返して、特定の曜日のみ除外する
const sceduleRule = CalendarApp.newRecurrence()
.addDailyRule()
.addWeeklyExclusion()
.onlyOnWeekdays([CalendarApp.Weekday.SUNDAY])
.times(10)
特定間隔(日ごと・隔週)
特定の間隔(.interval(number)
)でルールを休眠させることができます。intervalでは前段に記載され//ているルールによって間隔を決定してくれます。addWeeklyRule
では休眠期間1週間、addDailyRule
では休眠期間1日間になります。
// interval(1)で1週間になる
const sceduleRule = CalendarApp.newRecurrence().addWeeklyRule().interval(2).times(10);
// interval(1)で1日間隔になる
const sceduleRule = CalendarApp.newRecurrence().addDailyRule().interval(2).times(10);
第三水曜日のみ
addMonthlyRule
とonlyOnWeekday
をこねくり回して実現できないか試してみたのですが、実装が完成しませんでした。有識者の方教えてもらえると助かります。
でも、ここまでくるとGUIか月初めにトリガーで動かすプログラムを組んだ方が良い気がしています。てか月に一回しかやらない系のイベントなら手で設定するほうが確実だよな?
特定の日付の予定を取得する:getEventsForDay
ドキュメントとしては、こちらになります。指定した日付の予定情報をすべて取得します。サンプルでは、「実行当日の予定をすべて取得し、イベント名とイベントの合計時間を取得」となります。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const getEventsForDay = () => {
const startTime = new Date()
const options = {
// start: 0,
// max: 10,
// author: "",
// search: "",
// statusFilters: [
// CalendarApp.GuestStatus.OWNER,
// CalendarApp.GuestStatus.INVITED,
// CalendarApp.GuestStatus.YES,
// CalendarApp.GuestStatus.MAYBE,
// CalendarApp.GuestStatus.NO
// ]
}
const events = calendar.getEventsForDay(startTime, options)
// 各イベント情報をそれぞれ表示する
events.forEach((event) => {
console.log({
"id": event.getId(),
"title": event.getTitle(),
"time": (event.getEndTime() - event.getStartTime()) / 360 / 10000,
"owner": event.isOwnedByMe(),
"isAllDayEvent": event.isAllDayEvent(),
"eventType": event.getEventType().toString(),
"Mystatus": event.getMyStatus().toString()
})
})
// イベントの合計時間を何時間表記で取得する
const total = events.reduce((prev, event) => {
const isAllDayEvent = event.isAllDayEvent()
if (isAllDayEvent) { return prev }
return prev + (event.getEndTime() - event.getStartTime()) / 360 / 10000
}, 0)
Logger.log(total)
}
getEventsForDay
の引数は2つになります。時間情報は参照されずに、年・月・日の情報のみ使用されます。
名前 | 型 | 説明 |
---|---|---|
date | Date | イベント取得日時:必須 |
options | Object | イベントの詳細設定:オプション |
options情報としては、以下の情報を設定することができます。
名前 | 型 | 説明 |
---|---|---|
start | int | 返答されるイベントのインデックス(何番目のイベントから取得するか) |
max | int | 返答されるイベントの最大数 |
author | String | イベント参加者のフィルタ(メールアドレス) |
search | String | フィルタリングに使用される全文検索クエリ |
statusFilters | GuestStatus[] | フィルタリングに使用されるステータスの配列(参加・未定・不参加 etc…) |
特筆する点としては、search
・statusFilters[]
になります。search
では、全文検索クエリとなっています。部分一致で検索することができます。Prefixなどを付けて予定を登録すると管理がしやすいですね。
statusFilters
は、イベントに対するステータスで検索することができます。プロパティの説明はこちらにあります。カレンダー上で参加状況をちゃんと解答していれば、フィルターで情報を分析することができます。
こちらのサンプルでは、「招待されて参加したイベント・自分が発行したイベントの情報を取得して、合計時間を計算」となります。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const getEventsJoinTotalTime = () => {
const startTime = new Date()
const options = {
statusFilters: [
CalendarApp.GuestStatus.OWNER,
CalendarApp.GuestStatus.YES
]
}
const events = calendar.getEventsForDay(startTime, options)
// イベントの合計時間を何時間表記で取得する
const total = events.reduce((prev, event) => {
// 終日イベントを除外する
const isAllDayEvent = event.isAllDayEvent()
if (isAllDayEvent) { return prev }
return prev + (event.getEndTime() - event.getStartTime()) / 360 / 10000
}, 0)
Logger.log(total)
}
特定の期間の予定を取得する:getEvents
ドキュメントとしては、こちらになります。getEventsForDay
と使用感はほぼ一緒ですが、期間を明確に設定することができます。サンプルでは、「実行当日の8:00~18:30のイベントを取得」です。
const calenarID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const calendar = CalendarApp.getCalendarById(calenarID)
const getEvents = () => {
const startTime = new Date()
startTime.setHours(8, 0, 0)
const endTime = new Date()
endTime.setHours(18, 30, 0)
const events = calendar.getEvents(startTime, endTime)
events.forEach((event) => {
Logger.log({
"id": event.getId(),
"title": event.getTitle(),
"time": (event.getEndTime() - event.getStartTime()) / 360 / 10000,
"owner": event.isOwnedByMe(),
"isAllDayEvent": event.isAllDayEvent(),
"eventType": event.getEventType().toString(),
"Mystatus": event.getMyStatus().toString()
})
})
}
getEvents
で設定できる引数は3つです。使用時に注意が必要なのはendTime
です。こちらは、イベントの開始時間が、endTime
よりも速い場合はイベントがヒットします。
名前 | 型 | 説明 |
---|---|---|
startTime | Date | イベントの開始日時:必須 |
endTime | Date | イベントの終了日時(イベントの開始時間が含まれる場合は検索に含む):必須 |
options | Object | イベントの詳細設定:オプション |
options
で設定することができるのは、getEventsForDay
と同じになります。
終わり
今回は、GASでGoogle Calendarを操作する方法についてまとめました。こちらで紹介したコードと他の機能を組み合わせることで、Google Calendarを含めた自動化もできると思います。
今回紹介したコードを参考に、皆さんも自分なりのGoogle Calendar活用方法を見つけてみてください。もし、わからないことがあれば、コメント欄でお気軽に質問してくださいね。(第三水曜日を指定する方法がわかったらこっそり教えてください)
それでは、また次回の記事でお会いしましょう!