はじめに
私は、タスク時間管理としてToggl Trackを利用していました。
しかしながら、Toggl Trackを入力しつつ、普段使用する予定はgoogle Calendarにするというなんとも非効率な作業をしていました。
もちろんToggl Trackで完結するのがいいというのはその通りなのですが、現状のままでなんとか楽できないかと思い、GASを使って毎朝自動でGoogleカレンダーに同期する仕組みを構築を作成してみました。
前提
そもそもToggl以外を採用しようとも模索しました。
- TickTick
カレンダー機能が有料なため断念 - Timely
同様の理由でアプリ自体が有料なため断念 - Focus To-Do
拡張機能の追加が少々怖かった
Toggl公式が提供するGoogle Calendar Time Tracking Integrationというものも存在します。
以下のように、Calendarから起動できるのであって、google Calendarに追加するわけではないという問題があります。
以上のことから、Togglを用いつつ、できるだけローカルで完結できる様にするために、GASを利用して記録されるようにしていこうと思います。
GASのコード
※実際に動作した最新のコードをここに貼ります。
/**
* Toggl Track to Google Calendar Sync Script
* * 機能:
* 1. 毎朝6時に前日24時間分の実績を取得
* 2. 同期済みIDを保存し、重複登録を完全防止
* 3. プロジェクト名による自動色分け
*/
/**
* 設定:スクリプトプロパティ
* TOGGL_API_TOKEN : APIキー
*/
function debugSyncToday() {
const start = new Date(); start.setHours(0, 0, 0, 0);
const end = new Date(); end.setHours(23, 59, 59, 999);
syncTogglEntries(start, end);
}
function dailySyncAt6AM() {
const now = new Date(); now.setHours(6, 0, 0, 0);
const yesterday = new Date(now.getTime()); yesterday.setDate(yesterday.getDate() - 1);
syncTogglEntries(yesterday, now);
}
function syncTogglEntries(startTime, endTime) {
const props = PropertiesService.getScriptProperties();
const token = props.getProperty('TOGGL_API_TOKEN');
const calendar = CalendarApp.getDefaultCalendar();
const authHeader = 'Basic ' + Utilities.base64Encode(token + ':api_token');
// v9 API: プロジェクト名を取得するために meta=true を付与
const url = `https://api.track.toggl.com/api/v9/me/time_entries?start_date=${startTime.toISOString()}&end_date=${endTime.toISOString()}&meta=true`;
const response = UrlFetchApp.fetch(url, { 'headers': { 'Authorization': authHeader } });
const entries = JSON.parse(response.getContentText());
entries.forEach(entry => {
if (entry.duration < 0 || !entry.stop) return;
const togglId = entry.id.toString();
if (props.getProperty(`sync_${togglId}`)) return;
const start = new Date(entry.start);
const end = new Date(entry.stop);
const title = entry.description || '名称未設定タスク';
try {
const event = calendar.createEvent(title, start, end, {
description: `toggl_id:${togglId}`,
});
// プロジェクト名(projectName)で色を明確に分ける
// カレンダーの色ID: 8=グレー, 1=水色, 5=黄色, 10=緑
const pName = entry.project_name || "";
if (pName.includes("研究")) {
event.setColor("8");
} else if (pName.includes("運動")) {
event.setColor("10");
} else if (pName === "") {
event.setColor("1"); // プロジェクトなしは「薄い水色」
} else {
event.setColor("5"); // その他は「黄色」
}
props.setProperty(`sync_${togglId}`, 'true');
console.log(`Success: ${title} (${pName})`);
} catch (e) {
console.error(`Error: ${e.message}`);
}
});
}
function clearSyncFlags() {
/**
デバッグ用のプログラム(DebugSyncToday関数で複数回検証するためのプログラム)
これを起動しないと、カレンダー側にフラグが残ったままになるため、検証の際は必ず1回ごとに利用すること。
*/
const props = PropertiesService.getScriptProperties();
const allKeys = props.getProperties();
let count = 0;
for (let key in allKeys) {
if (key.startsWith('sync_')) {
props.deleteProperty(key);
count++;
}
}
console.log(count + "件の同期フラグを削除しました。これで再同期可能です。");
}
- 基本ロジックは、
dailySyncAt6AM()とsyncTogglEntries(startTime, endTime)のみで、それ以外の関数はデバッグで利用するプログラムのため、利用しなくても問題ありません。 - 環境変数が必要なので、APIキーに関しては、以下の方の記事を参考にしてください。
【Android】Toggl Track APIを使ってトラッキングの開始と停止をする(API v9バージョン)/ @tsumuchan(つむ ちゃん様)
自動化の設定(トリガー)
この処理を「全自動」にするため、GASのトリガーを設定します。
- GASエディタ左側の「時計アイコン(トリガー)」をクリック。
- 「トリガーを追加」を選択。以下のように設定:
- 実行する関数: dailySyncAt6AM
- イベントのソース: 時間主導型
- タイプ: 日付ベースのタイマー
- 時刻: 午前 6 時~7 時 (お好みで)
という設定が終われば、朝起きた時に、前日で実施したタスクが全てGoogleCalndar側に表示される様になります!
参考
TogglのデータをGoogleカレンダーに記録する方法 / haru様
時間管理アプリ:Toggl Track活用術 ~アプリ版、Integration、APIで「どこでもタイマー」/hosaka313様

