見出し画像

【GAS】googleカレンダーで簡易タスク管理する(定期タスクの自動登録と未実行の場合のリマインド機能のスクリプト)

こんにちは!私です。

私は自己管理にgoogleカレンダーを使うのでカレンダーに周期的な予定を追加するのですが、予定が実行されたかどうかは判定しないので、実行がなかった時のリマインドはありません。

例えば「週に1回ジムに行く」という周期予定をカレンダーに追加しても、行っても行かなくても翌週にタスクが再登録されてしまいます。

本来googleカレンダーにタスク管理機能はないので、TODO等と連動させる人は多いと思うのですが、そこまで管理項目が多くないのに複数ツールを使うのはそれはそれで管理が面倒でもあります。

ですので、googleカレンダーで完結する、簡易的な周期的なタスク管理機能をGASでつけてみました。

設定方法の詳細は記載しますので参考にしてみてください。


使い方

最初に、使用感を記載します。

後述するコードにタスクの初期設定(タスク名と周期)と、カレンダーに「済+タスク名」の予定を登録します。

カレンダーに「済+タスク名」の予定を登録する

(自動登録)週1の定期実行で初期登録したので、その日が終わった段階では翌週にタスクが追加されます。

翌週(7日後)にタスクが登録される

(自動登録)下記の様に終わっていないタスクがある場合リマインドで追加されます。

赤が自動登録した予定
緑がリマインドで登録された予定

(自動登録)タスクが完了されていれば、リマインドはされず、そこから更に7日後に予定が登録されます。

完了した予定は、先頭に「済」とつけるとリマインドされない

本来7日周期で実行したいので1日繰り越した場合は6日後に予定を登録して欲しいかもしれませんが、
何日も繰り越すと人の判断に任せる事が多くなるので、プログラムはシンプルになっています。

ですので、この場合だと、毎回1日~2日繰り越す事を見越して週1周期ではなく5~6日周期で設定してあげれば、実際は週1で行っている状況にし易いと思います。

初期設定

導入にあたって、後述するコードを一部修正する必要があります。修正点は下記です。

①2行目 【自分のgoogleメールアドレス】
カレンダー名ID=自分のgoogleメールアドレスを指定します

②自分用のタスクの追加
コード内に「爪切り」「ヘアカラー」の行がありますが、これがタスクです。新規に追加する場合は下記を中に追記します。

{ name: "【タスク名】", cycleDas: 【周期(日数)】, timeRange: { start: 【開始時刻】, end: 【開始時刻】 } },

例えばここに5日周期の「ジムに行く」という習慣を18時~19時に追加したい場合、中に下記を追加します。

{ name: "ジムに行く", cycleDas: 3, timeRange: { start: 18, end: 19 } },

修正例

  const tasks = [
    { name: "爪切り", cycleDas: 14, timeRange: { start: 19, end: 20 } },
    { name: "ジムに行く", cycleDas: 5, timeRange: { start: 18, end: 19 } },
    { name: "ヘアカラー", cycleDays: 90, timeRange: { start: 19, end: 20 } }
  ];

また、開始時刻と終了時刻は1時間単位でしか設定できません。実際の行動に移す場合には手動で時間を変える事もあるので不要と考えています。

最後の行以外はそれぞれのタスクはカンマ(,)で区切られているので注意

トリガーの設定
GASはトリガーを設定してあげると自動実行されます。
設定は
 周期:毎日実行
 時間:夜間ギリギリ
とします。

 周期:毎日実行 時間:午後11時~0時 起動

コード

全体コードは下記です。
これを上記修正してGASに貼ると実行してくれます。

function manageTasks() {
  const calendarId = '【カレンダーID】'; // カレンダーIDを指定 (Googleカレンダーの設定から取得可能)
  const calendar = CalendarApp.getCalendarById(calendarId);

  // タスクと周期の設定
  const tasks = [
    { name: "爪切り", cycleDays: 14, timeRange: { start: 19, end: 20 } },
    { name: "ヘアカラー", cycleDays: 75, timeRange: { start: 17, end: 20 } }
  ];

  tasks.forEach(function(task) {
    processTask(calendar, task.name, task.cycleDays, task.timeRange.start, task.timeRange.end);
  });
}

function processTask(calendar, taskName, cycleDays, startHour, endHour) {
  const now = new Date();

  // 今日のタスクを確認
  const todayStartTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), startHour);
  const todayEndTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), endHour);
  const todayEvents = calendar.getEvents(todayStartTime, todayEndTime);

  let hasCompletedTask = false;
  let hasUncompletedTask = false;

  todayEvents.forEach(function(event) {
    const eventTitle = event.getTitle();
    
    // 「済」で始まるタスクが今日の予定にあるかどうかを確認
    if (eventTitle.startsWith("済") && eventTitle.includes(taskName)) {
      hasCompletedTask = true;
    }
    
    // 「済」で始まらないタスクが今日の予定にあるかどうかを確認
    if (!eventTitle.startsWith("済") && eventTitle.includes(taskName)) {
      hasUncompletedTask = true;
    }
  });

  // 「済」タスクがある場合、次の周期日に新しいタスクを追加
  if (hasCompletedTask) {
    const nextTaskDate = new Date(now);
    nextTaskDate.setDate(now.getDate() + cycleDays);
    const nextTaskStart = new Date(nextTaskDate.getFullYear(), nextTaskDate.getMonth(), nextTaskDate.getDate(), startHour);
    const nextTaskEnd = new Date(nextTaskDate.getFullYear(), nextTaskDate.getMonth(), nextTaskDate.getDate(), endHour);
    calendar.createEvent(taskName, nextTaskStart, nextTaskEnd);
    console.log("New task added for: " + taskName + " on " + nextTaskDate);
    return;
  }

  // 未完了タスクがある場合、翌日にタスクを再設定
  if (hasUncompletedTask) {
    const nextDay = new Date(now);
    nextDay.setDate(now.getDate() + 1);
    const nextDayStart = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate(), startHour);
    const nextDayEnd = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate(), endHour);
    calendar.createEvent(taskName, nextDayStart, nextDayEnd);
    console.log("Uncompleted task rescheduled for: " + taskName + " on " + nextDay);
    return;
  }

  // 今日何もタスクがない場合は何もしない
  console.log("No tasks found for today: " + taskName);
}


以上です。
良いプログラムライフを!

この記事が気に入ったらサポートをしてみませんか?