1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

あなたの時間知覚を強化する:GASでカレンダーの説明欄をまとめるスクリプト

Posted at

3行で
・いつ何があったか時間の流れをはっきりとさせたくない?
・Googleカレンダーで記録して把握していこうぜ
・手間をGoogleAppScriptで省くぜ

前置き

歳をとると時間の感覚があいまいになっていくじゃないですか、
「あの出来事あったのって去年だっけ?」
と思っても実際には数年前だったりするわけで、

気づけば1か月や1年が終わっており
「何もせずに終わったなぁ」
と悲しい気持ちになるものです。

かくいう私も近年は時系列がふわふわで、
こりゃなんとかしたいと思い立った次第であります。

問題なのは「この時期に何をしていたのか?」が把握できていない事だと仮定し、
毎週の出来事を記録した上で、1か月ごとに内容をまとめることにしました。

これで後から見返しても「xx年のxx月はこれやってたな~」としみじみできて
とてもうれしい気持ちになることができること間違いなし、完璧な作戦と言えましょう。

さて、勘の良い方ならお分かりのはず、この一か月の出来事をまとめるという作業がなんとまぁ絶妙に手間でありまして、今回GASでスクリプトを作るにあたった経緯でございます。

それでは早速見ていきましょう

GASでカレンダーの説明欄をまとめるスクリプト

週間まとめweekの作成

week.png
まずは上記のように毎週の出来事をまとめるweekという繰り返し予定を、Googleカレンダーの好きな曜日に作っていきます。

自分は毎日カレンダーをチェックするので、「もしweekがあったら過去一週間の出来事をまとめる」という自分の脳内プログラムに従い、毎週の予定を書き記すことでしょう。

続いて脳内プログラムに従って一週間の内容をまとめた例を見ていきましょう
discription.png
上記のように説明欄に#から始まる出来事のカテゴリと、続けて内容を記入していきます。

このようにweekの説明欄に記載しておくことで、今回作成するスクリプトにより、毎月の出来事がカテゴリごとにまとめられるというわけです。

なお、ここで一点注意すべきことがありまして、
save.png
保存するときは「この予定」を選択しないと他のweekが消えてしまったりするため注意が必要です。

次は本題のスクリプトを作成する準備をしていきます。

スクリプトを作る準備をする

まずは「google apps script」でググり
google search.png

Start Scriptingに進み
gas.png

新しいプロジェクトを作成します
gas create.png

以下のようなページが表示されていれば準備は完了です。
editor.png

では早速スクリプトを作っていきましょう

スクリプトを作る

スクリプト全文

/*
カレンダーの先月のweekの説明欄をまとめ、実行月の1日にまとめた予定を出力する
動作にGoogleのCalendar APIと時間によるトリガーの設定が必要
*/

function main() {
  const calendarId = "カレンダーがあるアカウント@gmail.com";
  
  // 先月の月初日と月末日を取得
  const { monthStartDate, monthEndDate } = getLastMonth();  

  // 月初日と月末日から"week"というタイトルの予定を抽出
  const weekEvents = getWeekEvent(calendarId, monthStartDate, monthEndDate);

  // "week"というタイトルの予定から、説明欄を取得し#で記述したイベントごとに分類
  const eventCategories = getEventCategories(weekEvents);

  // イベントごとに分類したデータから1か月のまとめを作成
  const monthlySummary = getMonthlySummary(eventCategories);
  Logger.log(monthlySummary)

  // 作成した1か月のまとめをカレンダーに保存
  createMonthlySummaryEvent(calendarId, monthlySummary);
  Logger.log("実行完了");
}

function getLastMonth() { // 先月の月初日と月末日を取得
  var now = new Date();
  var monthStartDate = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  var monthEndDate = new Date(now.getFullYear(), now.getMonth(), 0);

  return { monthStartDate, monthEndDate };
}



function getWeekEvent(calendarId, monthStartDate, monthEndDate) { //"week"というタイトルの予定を抽出
  var events = Calendar.Events.list(calendarId, {
    timeMin: monthStartDate.toISOString(),
    timeMax: monthEndDate.toISOString(),
    singleEvents: true,
    orderBy: 'startTime'
  });

  var weekEvents = [];
  if (events.items && events.items.length > 0) { // eventが存在するなら続行
    for (var i = 0; i < events.items.length; i++) {
      var event = events.items[i];
      var summary = event.summary || ''; // タイトルが存在しない場合は空文字列を使用
      if (summary.toLowerCase().includes("week")) {
        weekEvents.push(event);
      }
    }
  }

  return weekEvents;
}

function getEventCategories(weekEvents) { // カレンダーの説明欄を取得
  var eventCategories = {}

  weekEvents.forEach(event => { // eventごとにループ
    const description = event.description; // 説明のテキストのみ抽出
    const lines = description.split('\n'); // 行ごとに分割

    let currentCategory = null; // カテゴリを保持するための変数を追加

    lines.forEach(line => { // 行ごとにループ
      if (line.startsWith('#')) { // #で始まる場合、カテゴリを格納
        currentCategory = line.replace("#", "").trim(); // カテゴリ名を更新
        if (!eventCategories.hasOwnProperty(currentCategory)) { // カテゴリ名が存在しないなら作成
          eventCategories[currentCategory] = [];
        }

      } else if (line.trim() != "") { // #以外で始まる場合、データが空白かどうか
        if (!eventCategories[currentCategory].includes(line.trim())) { // 既に保存していないか
          eventCategories[currentCategory].push(line.trim()); // カテゴリに追加
        }
      }
    });
  });

  return eventCategories;
}

function getMonthlySummary(eventDescriptions) { // 月間のイベントまとめを作成
  let monthlySummary = '';

  Object.entries(eventDescriptions).forEach(([key, value]) => {
    monthlySummary += `#${key}\n`;
    monthlySummary += value.join('\n') + '\n\n';
  });

  return monthlySummary;

}

function createMonthlySummaryEvent(calendarId, monthlySummary) { //1か月のまとめをカレンダーに保存
  const title = "MonthlySummary";
  const create_date = new Date(); // 実行時の日付(トリガーによって1日となる)を取得
  const description = monthlySummary;
  const calendar = CalendarApp.getCalendarById(calendarId)

  calendar.createAllDayEvent(title, create_date,{description: description});
}

ということで事前に作成して冷蔵庫で寝かせておいたスクリプトがこちら
main関数を見ればおおよそ分かるのと、長くなってしまうため関数の細かい説明は割愛します。

これを先ほどのエディタに貼り付けてから
mail.png
"カレンダーがあるアカウント@gmail.com";
という部分を自分のgoogleアカウントのgmailアドレスに変更し

save2.png
プロジェクトを保存します。

次に、GASでカレンダーを操作するために必要となるサービスを追加していきます。

Calendar APIの追加

横にある十字を選択し
service.png

Google Calendar APIを追加します
api.png
これにより、カレンダーを操作する便利な機能を使えるようになりました。

最後にこのスクリプトを毎月実行させるためのトリガーを設定していきましょう。

自動で実行するためにトリガーを設定

横にある目覚まし時計のアイコンから
timer1.png

トリガーを追加
timer2.png

以下のように毎月1日に実行されるよう設定してから
timer3.png

カレンダーへアクセスするためのスクリプトなので警告が出ますが、
許可していきます。

advancedから
timer4.png

許可画面へ
timer5.png

許諾を選択
timer6.png

これで、weekの予定が自動でまとめられ
1か月の出来事をまとめたカレンダーの予定が毎月1日に自動作成されます。

それではどのような結果が出るのか見ていきましょう

出力結果

month.png
上記のような一か月の出来事をまとめた予定が追加されます。
これにより「xx年のxx月はこんな出来事があったんだなぁ」と、
時間と出来事を明確に結びつけやすくなることでしょう、すばらしい限りであります。

最後に使っている感想などを述べたいと思います。

終わりに

個人の感想にはなりますが
「以前よりも時間に流される感覚が減ったな~」
というのが一番大きなところでしょうか

何もしていなかったように感じても
1か月のまとめを見ると思ったより色々やっていることが分かり、
安心感を覚えることができて大変満足しております。

年末に知人と振り返って楽しんでもよし、
出来事の時期を特定するために使ってもよしと、
たいへん便利なスクリプトとルーティンですので、取り入れてみてはいかがでしょうか。

ご拝読いただきありがとうございました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?