LoginSignup
4
5

More than 3 years have passed since last update.

GASを使ってGoogleカレンダーにカレンダーを追加する

Posted at

はじめに

コロナということもあって外出する機会も減り、仕事もリモートワークで
体を動かさなくなってきてしまった今日このごろですね。

以前はYouTubeでトレーニング動画をみて家でやってたのですが、半年で続かなくなっちゃいましたね。
そんな中、友人に誘われたので一緒にジムに入ることにしました。

どうせ入るなら元を取りたいし、どれくらい行ってるのかも気になるので
「いつ行ったかをメモろう!」ってなってたんですけど
毎回 "Y年m月d日 H:i:s 〜" って記録するのが面倒なので自動化したいな〜と思い、作るに至りました。

何を使って自動化するか

Googleカレンダー

結局のところ

  • 日付
  • 時間
  • 場所

をメモれるものってカレンダー系のアプリしかないな〜って思ったんですよね
普段から予定管理に使っているのもあって

$$\style{font-size:200%;font-weight:bold;align: center; font-family: "Helvetica Neue",Helvetica,"ヒラギノ角ゴ ProN W3","Hiragino Kaku Gothic ProN","メイリオ",Meiryo,sans-serif}{\text{Googleカレンダーでメモしよう!}}$$

となりました

Google App Script

Googleカレンダーを操作するならやっぱり同じGoogleが開発してるGASがいいのだろうとなって
$$\style{font-size:200%;font-weight:bold;align: center; font-family: "Helvetica Neue",Helvetica,"ヒラギノ角ゴ ProN W3","Hiragino Kaku Gothic ProN","メイリオ",Meiryo,sans-serif}{\text{GASを使おう!}}$$
となりました

どうやって自動化するか

GASのWebアプリ化

ボタン1つで打刻できれば良い = アクセスがきたらデータを追加
と置き換えれば話は早いです

仕組みを考える

カレンダーの追加って

  • タイトル
  • 開始時刻
  • 終了時刻

が必要で、
入室時に1回、退室時に1回と押すとしたら
退室時間がわかってから記録するようにしなければなりませんが、
「入室時の時間ってどこにメモっておけば...」が障害になりました

そこで調べてみたら、GASの機能に
Cache Servicehttps://developers.google.com/apps-script/reference/cache)
というものがありました
キャッシュを最長で6時間保持しておけるようなのでこれならいけそうです
※6時間以上トレーニングする人は他のやつ使ってください 笑

実装

アクセスできる用の関数を用意

アクセス時に呼び出される関数は名前が決まっていますので、今回はGET通信で呼び出されるdoGetを使用します

doGet.gs
//GET通信時に呼び出される
function doGet(){
}

クエリ文字列を取得

GASでクエリ文字列を取得する方法は以下の通りです
今回は入退室フラグとしてEoLFlg(Enter or Leave Flag)を使います

doGet.gs
function doGet(e){
  var EoLFlg = e.parameter.EoLFlg;
}

追加するカレンダーの取得

今回は「ジム」というカレンダーを作りました
カレンダーIDからそのカレンダーのオブジェクトを取得できるので、そのように記載します

doGet.gs
const calendarId = '[対象カレンダーのカレンダーID]←カレンダーから 設定>マイカレンダーの設定>カレンダーの統合から確認できます';
const calendar = CalendarApp.getCalendarById(calendarId);

カレンダーのクラスの使い方を詳しく知りたい方は以下の公式ドキュメントへどうぞ
https://developers.google.com/apps-script/reference/calendar/calendar-app

キャッシュを使う準備

キャッシュを使えるように関数を準備します
※他の方のコードの引用なので、最後に参考文献として載せてあります

makeCache.gs
// キャッシュの保存・取得をする関数 ※Qiitaからの引用(https://qiita.com/golyat/items/ba5d9ce38ec3308d3757)
function makeCache() {
  const cache = CacheService.getScriptCache();
  return {
    get: function(key) {
      return JSON.parse(cache.get(key));
    },
    put: function(key, value) {
      cache.put(key, JSON.stringify(value), 21600);
      return value;
    }
  };
}

実装(コード)

以上で完了です!
定数を変えればほぼコピペで使えるソースを下記に載せておきますね
細かく説明を載せておきますので、コピペして使う前に確認をしてください

addCalendar.gs
// 定数の宣言(カレンダーID、カレンダーオブジェクト、追加するカレンダーのタイトル、場所)
const calendarId = '{カレンダーID}';
const calendar = CalendarApp.getCalendarById(calendarId);
const title = '{タイトル}';
const location = '{場所}';
const option = {'location':location};

// キャッシュ周りの定数(保存時間、関数、キーとして使用するフラグの値)
const cacheTime = 21600;
const cache = makeCache();
const EoLFlgs = ['E', 'L'];

// GETでのアクセス時に対応
function doGet(e){
  var EoLFlg = e.parameter.EoLFlg;

  // EoLFlgが E 又は Lの時に起動
  if( EoLFlgs.indexOf(EoLFlg) != -1){
    var date = new Date();
    cache.put(EoLFlg, Utilities.formatDate( date, 'Asia/Tokyo', 'YYYY/MM/dd H:m:s'));

    switch(EoLFlg){
      // E:入室時 念の為退室時刻のキャッシュをクリア
      case "E":
      cache.put('L', null);
      break;

      // L:退室時 入室時刻 < 退室時刻 となっていればカレンダーに追加
      case 'L':
      var startTime = cache.get(EoLFlgs[0]);
      var endTime = cache.get(EoLFlgs[1]);
      cacheClear();
      if( startTime < endTime ){
        var result = calendar.createEvent(title, new Date(startTime), new Date(endTime), option);
      }else{
        return HtmlService.createTemplateFromFile('ERROR').evaluate();
      }
      break;
    }
    return HtmlService.createTemplateFromFile('success'+EoLFlg).evaluate();
  }
}

// キャッシュの保存・取得をする関数 ※Qiitaからの引用(https://qiita.com/golyat/items/ba5d9ce38ec3308d3757)
function makeCache() {
  const cache = CacheService.getScriptCache();
  return {
    get: function(key) {
      return JSON.parse(cache.get(key));
    },
    put: function(key, value) {
      cache.put(key, JSON.stringify(value), cacheTime);
      return value;
    }
  };
}

// キャッシュクリア用関数
function cacheClear(){
  // それぞれのキャッシュをクリア
  for(var i = 0; i < EoLFlgs.length; i++){
    cache.put(EoLFlgs[i], null);
  }
}

定数

addCalendar.gs
// 定数の宣言(カレンダーID、カレンダーオブジェクト、追加するカレンダーのタイトル、場所)
const calendarId = '{カレンダーID}';
const calendar = CalendarApp.getCalendarById(calendarId);
const title = '{タイトル}';
const location = '{場所}';
const option = {'location':location};
calendarId

追加するカレンダーのID
Googleカレンダーの設定画面に書かれているものをいれる(図のオレンジの箇所)
スクリーンショット 2021-03-21 21.14.17.png

title

カレンダーのタイトル
スクリーンショット 2021-03-21 21.22.05.png

location

カレンダーに設定される場所
スクリーンショット 2021-03-21 21.24.18.png
※optionで説明等も追加することができます

定数(キャッシュ等)

addCalendar.gs
// キャッシュ周りの定数(保存時間、関数、キーとして使用するフラグの値)
const cacheTime = 21600;
const cache = makeCache();
const EoLFlgs = ['E', 'L'];
cacheTime

キャッシュの保存時間 最大6時間(21600秒) ※makeCacheで使用

cache

makeCacheの定数化

EoLFlgs

クエリ文字列で使用するEoLFlgの配列
E = Enter(入室)
L = Leave(退室)
のフラグとして使用

doGet

addCalendar.gs
// GETでのアクセス時に対応
function doGet(e){
  var EoLFlg = e.parameter.EoLFlg;

  // EoLFlgが E 又は Lの時に起動
  if( EoLFlgs.indexOf(EoLFlg) != -1){
    var date = new Date();
    cache.put(EoLFlg, Utilities.formatDate( date, 'Asia/Tokyo', 'YYYY/MM/dd H:m:s'));

    switch(EoLFlg){
      // E:入室時 念の為退室時刻のキャッシュをクリア
      case "E":
      cache.put('L', null);
      break;

      // L:退室時 入室時刻 < 退室時刻 となっていればカレンダーに追加
      case 'L':
      var startTime = cache.get(EoLFlgs[0]);
      var endTime = cache.get(EoLFlgs[1]);
      cacheClear();
      if( startTime < endTime ){
        var result = calendar.createEvent(title, new Date(startTime), new Date(endTime), option);
      }else{
        return HtmlService.createTemplateFromFile('ERROR').evaluate();
      }
      break;
    }
    return HtmlService.createTemplateFromFile('success'+EoLFlg).evaluate();
  }
}
var EoLFlg = e.parameter.EoLFlg;

クエリ文字列から取得したEoLFlg

流れの説明
  1. EoLFlgの値が" E" もしくは "L"だった場合にのみ起動
  2. 起動時の時刻をキャッシュとして保存
  3. Eの場合(入室時):Lのキャッシュをクリア
  4. Lの場合(退室時):それぞれのキャッシュ情報を取得後、キャッシュクリア
  5. EのキャッシュがLのキャッシュより過去日になっていれば、カレンダーに追加
  6. EのキャッシュがLのキャッシュより過去日になっていなければ、エラー表示
  7. 正常に処理が終われば成功の表示

return HtmlService.createTemplateFromFile('ERROR').evaluate();
return HtmlService.createTemplateFromFile('success'+EoLFlg).evaluate();
はエラー時、成功時にHTMLを出力するための記述なので、
HTMLを3ファイル追加してください
* ERROR.html
* successE.html
* successL.html


キャッシュ操作の関数

addCalendar.gs
// キャッシュの保存・取得をする関数 ※Qiitaからの引用(https://qiita.com/golyat/items/ba5d9ce38ec3308d3757)
function makeCache() {
  const cache = CacheService.getScriptCache();
  return {
    get: function(key) {
      return JSON.parse(cache.get(key));
    },
    put: function(key, value) {
      cache.put(key, JSON.stringify(value), cacheTime);
      return value;
    }
  };
}

// キャッシュクリア用関数
function cacheClear(){
  // それぞれのキャッシュをクリア
  for(var i = 0; i < EoLFlgs.length; i++){
    cache.put(EoLFlgs[i], null);
  }
}
makeCache

キャッシュを操作する関数
cache.get(key)で引数のキーのキャッシュを取得できる
cache.put(key, value)で引数のキーのキャッシュを設定できる
※上記の定数で指定したchcheTimeはここで使う

cacheClear

キャッシュクリアする関数
EoLFlgsのループをし、nullを入れる

以上が処理の流れと実装内容になります

さいごに

今回はGoogle App Scriptを用いてGoogleカレンダーにカレンダーを追加する方法について書きました
勉強のメモとして書きましたが、GASを使ってなにかしたいと思っている人の参考になれば嬉しいです

最後までお読みいただきありがとうございました

参考文献

  • Cache Serviceを詳しく説明してくれている方の記事

  • タイムゾーンの変更方法について詳しく説明してくれている方の記事

備考

自分はiPhoneのショートカットで
「ジムに到着したら」「ジムを出発したら」ってオートメーションに
今回作ったWebアプリにアクセスするショートカットを実行できるようにして使ってます

4
5
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
4
5