GASを使用してGoogle CalendarのLocationに文字列を記録したイベントを削除する
はじめに
MMORPGのドラゴンクエスト10のエンドコンテンツ、常闇の聖戦をかなり頑張ってやっていた時期がありました。日によって常闇ボスの強さのレベルが変わっており、それを10年分Google Calendarに登録していたのですが、常闇は殆どやらなくなり、カレンダーで目にするのが煩わしくなっておりました。
カレンダー自体を消して作り直しても良かったのですが、常闇以外の予定は備忘録として残したかったので、GASを使用して特定のイベントをカレンダーから削除するスクリプトを作りました。参考にしたのは下記のURLの記事です。
注意点
GASは無償ライセンスですと、使用するにあたって制限事項があります。仕様書を読み込んでいないのでうろ覚えですが、1実行は6分以内、多くのカレンダーイベントの削除?ができないなどです。
10年分のイベントなので約3650件で、スクリプト1回では処理しきれません。1実行を6分以内に収める時間判定、遅延処理、トリガー、プロパティサービスという仕組みを使用しました。
トリガーというのはWindowsで言うところのタスクスケジューラみたいなものです。手動実行して5分後にトリガーを登録し、トリガーは更に1分後に関数を再帰呼出ししております。
プロパティサービスはグローバル変数というか、ローカルストレージみたいなものです。日付の範囲のどこまでを削除実行したのかは永続的に参照する必要があったので使用しています。
日付の範囲を作成→時間判定→トリガー処理→文字列検索・カレンダーのイベント削除→遅延処理というステップで処理します。
コード
function myFunction() { //開始時間 var startTime = new Date(); //カレンダーIdから取得 var cal = CalendarApp.getCalendarById("ここにはカレンダーIdを入れます"); //途中経過保存用 var properties = PropertiesService.getScriptProperties(); //何日目まで処理したかを保存するときに使用するkey var startDateKey = "startDate"; //トリガーIDを保存するときに使用するkey var triggerKey = "trigger"; //開始日を取得 var startDate = properties.getProperty(startDateKey); if (!startDate) { //初めて実行する場合は指定日付で初期化 startDate = new Date("ここには開始日付を入れます"); } else startDate = new Date(startDate); //終了日を入力 var endDate = new Date("ここには終了日付を入れます"); var events = cal.getEvents(startDate, endDate); for (var n = 0; n < events.length; n++) { var diff = parseInt((new Date() - startTime) / (1000 * 60)); //5分経過していたら処理を中断 if (diff >= 5) { //処理日を保存 var dateStr = Utilities.formatDate(events[n].getStartTime(), "JST", "yyyy/MM/dd"); properties.setProperty(startDateKey, dateStr); //トリガーを発行 setTrigger(triggerKey, "myFunction"); return; } if (events[n].getLocation().match(/ここには検索文字列を入れます/)) { //イベント削除 events[n].deleteEvent(); } //1秒遅延 Utilities.sleep(1000); } //全て実行終えたらトリガーと何日目まで実行したかを削除する deleteTrigger(triggerKey); properties.deleteProperty(startDateKey); } //指定したkeyに保存されているトリガーIDを使って、トリガーを削除する function deleteTrigger(triggerKey) { var triggerId = PropertiesService.getScriptProperties().getProperty(triggerKey); if(!triggerId) return; ScriptApp.getProjectTriggers().filter(function(trigger){ return trigger.getUniqueId() == triggerId; }) .forEach(function(trigger) { ScriptApp.deleteTrigger(trigger); }); PropertiesService.getScriptProperties().deleteProperty(triggerKey); } //トリガーを発行 function setTrigger(triggerKey, funcName){ //保存しているトリガーがあったら削除 deleteTrigger(triggerKey); var dt = new Date(); //1分後に再実行 dt.setMinutes(dt.getMinutes() + 1); var triggerId = ScriptApp.newTrigger(funcName).timeBased().at(dt).create().getUniqueId(); //あとでトリガーを削除するためにトリガーIDを保存しておく PropertiesService.getScriptProperties().setProperty(triggerKey, triggerId); }
解決できなかったこと
何故かトリガーが途中で記録されずに終了してしまうことがありました。何度かスクリプトを手動で実行して全てのイベントを削除できました。
2019/08/11
全体的に変数の命名やインデント、セミコロンの入れ忘れ、ループ処理の負荷を見直し、コードを書き換えました。
免責事項
本ページに掲載されているスクリプトの使用、または使用不具合等により生じたいかなる損害に関しましてブログ管理人は一切責任を負いません。
第5回横浜鶴見川ハーフマラソンを振り返る。
はじめに
4/14にスポーツワン主催の第5回横浜鶴見川マラソンでハーフマラソンを走ってきました。ここにエントリーした理由は主に3つあります。
1)Runnetでの検索
2)職場の後輩から鶴見川の河川敷コースが走りやすいと聞いていたので興味あった
3)前回(三浦国際市民マラソン)のリベンジでハーフでサブ2を目指す
GarminのGPSウォッチで走行ログを取ったので、データを見ながら振り返りたいと思います。
コース

鶴見川を南から北に向かって往復5kmのコースを4周しました。河川敷なので平坦なコースですが、1km過ぎたあたりに高架下があり、そこは下り坂。当然復路は上りになり、10m程度の距離ですがきつく感じました。当日は北風が吹いており、帰りは向かい風になります。4m程度の軽風で気温は16℃、降雨もなかったのでハーフを走るには良いコンディションだったと思います。ハーフマラソンの部門は50人程度だったでしょうか、小規模で混雑等なく、走りやすかったのではないかと。
スタッフの方はアルバイトの高校生の方が多かったと思いますが、沿道で応援してくれたので励みになりました。主催の株式会社スポーツワンの皆様、楽しいイベントをありがとうございました。
トイレ・更衣室
トイレは河川敷にある公衆トイレのみでした。男女別のテントが用意してあって、そこで着替えができました。
結果
| 距離(km) | 区間タイム | 到達時間 |
| 1 | 5:17 | 0:05:17 |
| 2 | 5:11 | 0:10:28 |
| 3 | 5:14 | 0:15:42 |
| 4 | 5:23 | 0:21:05 |
| 5 | 5:33 | 0:26:38 |
| 6 | 5:25 | 0:32:04 |
| 7 | 5:19 | 0:37:22 |
| 8 | 5:18 | 0:42:41 |
| 9 | 5:37 | 0:48:17 |
| 10 | 5:28 | 0:53:45 |
| 11 | 5:37 | 0:59:22 |
| 12 | 5:21 | 1:04:44 |
| 13 | 5:24 | 1:10:07 |
| 14 | 5:18 | 1:15:25 |
| 15 | 5:27 | 1:20:53 |
| 16 | 5:33 | 1:26:26 |
| 17 | 5:29 | 1:31:55 |
| 18 | 5:31 | 1:37:26 |
| 19 | 5:32 | 1:42:58 |
| 20 | 5:51 | 1:48:48 |
| 20.92 | 5:20 | 1:53:42 |
5分30秒前後のペースを守ってサブ2を達成できました。到達順位は35位でした、早い人は4分/kmペースを維持できるので、僕から見ると超人に見えますね。
良かったところ
1)マシンや自重の筋力トレーニング
レッグプレス、レッグレイズやニーリフト、ニータックの効果なのか、おしりや脹脛に痛みや疲労がおきることはなかったです。
2)朝食
アミノバイタルやプロテイン含めて1500kcalとったので最後までスタミナ切れは起こさなかったです。
先行するランナーの後ろについていたので、地味に風よけとペースメーカーとして役に立ちました。
4)給水
4km地点でスポーツドリンクを飲みましたので脱水にもならなかったです。
5)サブ2
目標を達成できて嬉しかったです。
6)コンタクトレンズ
メガネが曇るときになってしまうので。
悪かったところ
1)ゴール後に右肩と右膝に激痛
自己流で走っているので、右に傾いていてランニングフォームが悪いのかもしれません。
2)荷物が多かった
ランウェアに近い状態で行ったほうが身軽で楽だったかもしれません。
マタイ受難曲/バッハ・コレギウム・ジャパン@彩の国さいたま芸術劇場 音楽ホール
はじめに
自分にとって、今年初のバッハ・コレギウム・ジャパンの公演を彩の国さいたま芸術劇場で聞いてきました。受難週にあたる今日の曲目はマタイ受難曲です。
全曲通して3時間近くもあるバッハの大作を聞くのは、僕にとっても音楽を通した精神の修行のような意味があります。昔、鈴木雅明音楽監督が受難曲とは聖書の記事を通して、個人の信仰・信条と向き合う音楽、なんて仰っていたように思います。素晴らしい曲であるものの、通して聞くのは感動とともに結構しんどく、演じるオケの皆さんには感謝しかありません。
例年であればBCJの主戦場であるオペラシティコンサートホールに行くんですが、今回は彩の国さいたま芸術劇場にしました。
結論から言えば、オペラシティコンサートホールよりも小規模のホールの1階席だったので、今までにない発見があり良かったと思いました。また、今回のオケはチェロが鈴木秀美、コンマスが寺神戸亮でBCJオールスターと言う布陣だったのもラッキーでしたね。公演の前にマタイの新録音をしたそうなので、良い記念にもなり、アルバムも楽しみです。
席は9割ぐらいは埋まっていたように思います。埼玉まで聞きに来るなんて、筋金入りの古楽マニア、BCJマニアでしょうね。コンサートプログラムも鈴木御大の和訳がのっており、良いプレゼントを頂いたと思います。僕はドイツ語も聖書の知識も少ないのでマタイを楽しむ良い道標になると思います。
気づいたこと
- パイプオルガンにフェンダーミラーみたいなものが2つついていた。
これは後ろの指揮者を見るためだったのかなぁと思います。
オペラシティだと2階にパイプオルガンが配置されており、ミラーはなかった気がします。 - Erbarme dichではチェロは弓ではなく指だった。
CDの音源では「ポンポン」何がなってるのかなぁとずっと不思議でした。 - Komm, suses Kreuzがヴィオラ・ダ・ガンバのソロと気がついた。
バスのアリアで好きな曲なんですが、これがガンバの音色なんだなぁと。 - 激しい曲はより激しく、沈鬱な曲は弱く微妙に。
鈴木雅明音楽監督の振りのアクションに応じてオケが緩急つけた演奏になっており、メリハリを感じる素晴らしい演奏でした。
2019皐月賞の予想
中山芝2000mの過去10年の分析
- ルメール騎手が驚異の勝率30%で、軸からは外せない。
サートゥルナーリア - デムーロ騎手は勝率14%程度。意外と乗れていない
アドマイヤマーズ - 武豊騎手は連対率17%程度で、平成の天才も近年は不振傾向かも。
ファンタジスト - ダイワメジャー産駒は勝率7%程度で、このコースを苦手としている。
アドマイヤマーズ - ロードカナロア産駒は勝率21%と軸には外せない。
サートゥルーナーリア、ファンタジスト - ディープインパクト産駒は連対率24%と安定感がある。
ダノンキングリー、サトノルークス - ケープブランコ産駒はこのコースで着なし。オープン馬1頭なのでしかたないか。
ランスオブプラーナ
皐月賞の過去10年の分析
2019桜花賞の予想
阪神芝1600mの過去10年の分析
- コース形態からはルメール騎手が勝率29%、連対率43%と驚異の数字。
紐からは外せないか。
グランアレグリア - デムーロ騎手は連対率35%。得意としているコース。
アクアミラビリス - 北村友一騎手は勝率5.6%。うーん、という数字。
クロノジェネシス - ディープインパクト産駒は勝率11.1%。このコースは思った以上に得意ではない。
ダノンファンタジー、グランアレグリア、シェーングランツ、ノーブルスコア、レッドアステル - ロードカナロア産駒は驚異の勝率20%。
ルガールカルム - バゴ産駒は連対率47%であり、紐からは外せないか。
クロノジェネシス - 藤澤厩舎は複勝率65%。狙い通りに取ってきている。
シェーングランツ、グランアレグリア