はじめに
仕事で使ってるGoogleカレンダーをチームで管理して、カレンダー表示+一覧化してほしいとのことで、今回やったことの備忘録を残します。
そのため今回はスプレッドシートに予定を出力するまでとなります。
準備するもの
- Googleアカウント
- Googleスプレッドシート
- GASエディタ
- Googleカレンダー
簡単な流れ
- Googleカレンダーで設定変更
- 各ユーザーのカレンダーIDを取得
- Googleカレンダーで他のユーザーの閲覧を許可
- スクリプトを書いていく
- 挙動確認
実際にやってみた
今回はユーザー①のカレンダーにユーザー②の予定を追加して、ユーザー①のスプレッドシートで予定を管理していきます。
-
Googleカレンダーでの設定
- カレンダーIDを取得(人数分)
- 他のユーザーの閲覧を許可する
-
招待する側(ユーザー②)のGoogleカレンダーを表示する
-
今回は予定を参照できればOKなので、権限は「予定の表示(すべての予定の詳細)」にしますが、必要最低限の権限にすることをお勧めします。
-
招待されたユーザー(ユーザー①)のGmailを開き、招待メールを確認
-
メール内の「このカレンダーを追加」を押下
-
自動でGoogleカレンダーに移動して、「カレンダーを追加」とポップアップが出るので、「追加」を押下
-
-
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); } }
-
挙動確認
- GASエディタの「実行ボタン」を押下
- 初回は「認証が必要です」みたいなポップアップが表示されるので、「続行」→アカウントを選択→「詳細」→「安全ではないページに移動」→「許可」と押下していく
- 再度「実行」ボタンを押下
- スプレッドシートに戻って、予定が表示されればOK
今後のアイディア
- トリガー設定をしてこの処理をバッチ化、取得した予定をLINEやGmail、Slackなどに毎朝送るようにすればスプレッドシートを開かずに1日の予定を確認できる
- ↑をやるならその日に入った予定の扱いをどうするか。。そこまで気にしないか、予定が入ったらリアルタイムで知らせるとか。
まとめ
今回はGoogleカレンダーでしたが、そのほかのカレンダーアプリ(TimeTreeとか)との連携とかも今度やってみたいと思います。
こうした方がシンプルにできる、ここがわかりづらい等ありましたらコメントください!
よければいいねもお願いします!
2025/02/01追記
- ID取得を柔軟に対応できるようにしゅうせ
上記のコードではユーザの追加、削除等に対応しにくいと思いますので、少しメソッドを追加していきます。
作戦としては指定したシートにID、メールアドレス、ユーザ名を入力して、それを取得するメソッドを追加します。- ユーザ情報シートを作成
- 以下メソッドを追加、その他コードを修正
- 追加メソッド
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); // スプレッドシートに記入 }
- 追加メソッド
- ユーザ情報シートを作成
- メールアドレス→ユーザ名に変換
以前はメールアドレスを表示していましたが、(次の記事では)LINEに送信となるとメッセージの中にメールアドレスがあると見づらいなと。。
そのためメールアドレスからユーザー名に変換する処理を追加します。
といっても上記で追加したメソッドを流用します。- 修正したコード
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;
}
追記したせいで、だいぶ記事が長くなってしまった。。すみません。。
参考文献
以下のサイトを参考にさせていただきました。ありがとうございます。