GASのTips

GASのトリガーを月末に設定する方法

月末トリガー GASのTips

みなさんこんにちは!GASおじさんです。

今日は2023年1月31日。つまり月末です。

月末は経理の締め作業など、いろいろと忙しくなる1日ではないでしょうか?

プログラムにできる仕事はプログラムに任せて、できるだけ余裕のある1日を過ごしていきたいですね。

ということで本日は、「GASのトリガーを月末に設定する方法」について解説していきます。

GASのトリガーを月末に設定する方法

まずは結論からです。

以下はsendMail関数を毎月月末の正午12時00分に実行するためのスクリプトとなっています。

function sendMail() {
  let recipient = Session.getActiveUser().getEmail();
  let subject = '月末のお知らせ';
  let body = '今日は月末です。明日から新しい月が始まります。';
  GmailApp.sendEmail(recipient, subject, body);
  setTrigger(); // メール送信後にトリガー設定
}

function setTrigger() {
  let triggers = ScriptApp.getScriptTriggers();
  for(let trigger of triggers){
    let funcName = trigger.getHandlerFunction();
    if(funcName == 'sendMail'){
      ScriptApp.deleteTrigger(trigger);
    }
  }

  let now = new Date();
  let y = now.getFullYear();
  let m = now.getMonth();
  let date = new Date(y, m+2, 0, 12, 0);
  console.log(y, m, date);
  ScriptApp.newTrigger('sendMail').timeBased().at(date).create();
}

※こちらはあくまでsendMail関数をトリガー実行するためのスクリプトです。コピペして運用する際は、13行目と23行目の「sendMail」を実行したい関数名に書き換えてから運用してください

結論のみ知りたい人はここまで!

ここから先はコードの詳しい解説をしていきます。

コード解説

まずは定期実行したいサンプルスクリプトを用意

ということでやっていきましょう。

今回は以下のsendMail関数を毎月月末の昼12時に実行したいというケースを想定して解説します。

function sendMail() {
  let recipient = Session.getActiveUser().getEmail();
  let subject = '月末のお知らせ';
  let body = '今日は月末です。明日から新しい月が始まります。';
  GmailApp.sendEmail(recipient, subject, body);
}

まずはこちらのスクリプトをエディタに貼り付けてみてください。

貼り付けたら一度実行して、権限承認しておきましょう。

「特定の日時」トリガーについて

さて、このsendMail関数を毎月月末の12時00分に実行したいのですが、ここでまず「特定の日時」トリガーについて説明しておきます。

トリガー設定画面を開いて、イベントのソースを「時間主導型」にすると、トリガーのタイプに「特定の日時」が選べるようになります。

そして「日時を入力」の欄の中に、「YYYY-MM-DD HH:MM」形式で日時を入力すると、その時刻ぴったりにトリガー実行することができるのです。

上記画像では「2023-01-31 12:00」と入力して保存しました。

こうすると、2023年1月31日の12時00分にsendMail関数が実行されます。

「特定の日時」トリガーをGASで設定するスクリプト

とりあえず「特定の日時」トリガーを手動で設定してみました。

今度はこれを手動ではなく、スクリプトを書いて設定してみたいと思います。

以下のsetTrigger関数を実行すると、2023年1月31日の12時00分にトリガー設定をすることができます。

function setTrigger() {
  let date = new Date(2023, 0, 31, 12, 0);
  ScriptApp.newTrigger('sendMail').timeBased().at(date).create();
}

試しにコードをコピペして実行してみましょう。

setTrigger関数を実行すると…

トリガーが1個増えてますね!

追加されたトリガーを確認すると、手動で設定したときと同じ内容で設定できていることが確認できると思います。

ということで、GASのトリガーはスクリプトを書くことでも設定できるということがわかりました!

new Date()で月末を返す方法

さて、ここで一旦以下のsetTrigger関数の2行目に注目してください。

function setTrigger() {
  let date = new Date(2023, 0, 31, 12, 0);
  ScriptApp.newTrigger('sendMail').timeBased().at(date).create();
}

GASやJavaScriptの日付の扱いに慣れている人は、上記2行目の内容が、「2023年1月31日12時00分」を表していることがわかると思いますが、初心者の人がこれを理解するのが少し難しいんですよね…

new Dateで日付を生成するときは、引数に(年, 月, 日, 時, 分, 秒, ミリ秒)と指定することで、任意の日時を返すことができます。

このときの注意点として、第2引数の「月」は、「マイナス1の数値を指定する」というのがあります。

  • 1月を表したいときは「0」を指定
  • 2月を表したいときは「1」を指定
  • 12月を表したいときは「11」を指定

する必要があります。

また、「秒」や「ミリ秒」は省略することができるので、(年, 月, 日, 時, 分)でもOKです。

これらを踏まえると、「2023年1月31日12時00分」を表したいときは、new Date(2023, 0, 31, 12, 0)となるんですね。

練習のため、いくつか例をあげてみます。

  • 2023年1月1日9時30分」を表したいときは、new Date(2023, 0, 1, 9, 30)
  • 2023年2月22日22時22分」を表したいときは、new Date(2023, 1, 22, 22, 22)
  • 2023年12月31日23時59分」を表したいときは、new Date(2023, 11, 31, 23, 59)

となります。どうでしょう、慣れてきたでしょうか?

ではここで問題です。以下は何を表しているでしょうか?(時と分は省略します)

new Date(2023, 1, 0)

  • 第1引数は「2023」なので、これはそのまま「2023年」です。
  • 第2引数は「1」なので、これはつまり「2月」ですね。
  • さて、第3引数が「0」となっています。これはどういうことでしょうか?

「2023年2月0日」なんて日付は存在しません。困りましたね…

さて、もったいぶらずに正解を言うと、これは「2023年1月31日」を表すことになります。

「2月0日」は「2月1日」の1日前ということで、日付を自動的に計算して1月31日を返してくれるわけですね。

つまり、月末の日付を生成したいときは、new Date()の第3引数に「0」を指定すればいいということになります。

  • 2023年1月31日を生成したいときは、new Date(2023, 1, 0)
  • 2023年2月28日を生成したいときは、new Date(2023, 2, 0)
  • 2023年12月31日を生成したいときは、new Date(2024, 0, 0)

というかんじですね。

また、閏年にも対応可能なので、2024年2月29日を生成したいときは、new Date(2024, 2, 0)とすればOKです。

年と月を変数化

ということでこれを利用して、毎月月末にトリガー実行できるように、各数値を変数化していきましょう。

setTrigger関数を以下のように書き換えてみてください。

function setTrigger() {
  let now = new Date();
  let y = now.getFullYear();
  let m = now.getMonth();
  let date = new Date(y, m+2, 0, 12, 0);
  ScriptApp.newTrigger('sendMail').timeBased().at(date).create();
}

注意点としては、5行目の第2引数をm+2とすることと、第3引数を0にすることですね。こうすることで、「再来月の0日」、つまり「来月の月末」という日付を指定してトリガー設定することができます。

sendMail関数の中でsetTrigger関数を呼び出す

次にsendMail関数の中でsetTrigger関数を呼び出します。

sendMail関数を以下のように書き換えてみてください。

function sendMail() {
  let recipient = Session.getActiveUser().getEmail();
  let subject = '月末のお知らせ';
  let body = '今日は月末です。明日から新しい月が始まります。';
  GmailApp.sendEmail(recipient, subject, body);
  setTrigger(); // メール送信後にトリガー設定
}

6行目でsetTrigger関数を呼び出しています。

こうすることで、

  • 1月31日の12時00分にメール送信後、2月28日の12時00分にトリガー設定される
  • 2月28日の12時00分にメール送信後、3月31日の12時00分にトリガー設定される
  • 3月31日の12時00分にメール送信後、4月30日の12時00分にトリガー設定される
  • 以下繰り返し

という形で、ドミノ倒しのようにトリガー設定が行われることになるので、これで毎月月末の12時00分にトリガー実行することができます!

過去のトリガーを消去するスクリプトを実装

これで実装完了です!

・・・といいたいところですが、あともうひとつ、やっておきたいことがあります。

現状のままだと、毎回このスクリプトが実行されるたびに、新たなトリガーが追加されてしまいます。以下のようにどんどん過去のトリガーが溜まっていってしまうんですね。

こうなるとトリガーの管理が大変になってしまうので、必要のない過去のトリガーについては削除してしまいたいです。

ということで、setTrigger関数を以下のように書き換えましょう。

function setTrigger() {
  let triggers = ScriptApp.getScriptTriggers();
  for(let trigger of triggers){
    let funcName = trigger.getHandlerFunction();
    if(funcName == 'sendMail'){
      ScriptApp.deleteTrigger(trigger);
    }
  }

  let now = new Date();
  let y = now.getFullYear();
  let m = now.getMonth();
  let date = new Date(y, m+2, 0, 12, 0);
  ScriptApp.newTrigger('sendMail').timeBased().at(date).create();
}

2〜8行目を新たに書き加えました。

こうすることで、過去に設定されたトリガーを削除した後に、新たなトリガーを追加することができます。

試しにsetTrigger関数を実行してみます。

その後トリガー画面を確認してみると…

不要なトリガーは削除され、必要なトリガーが1個だけ設定されていることが確認できました!

これにて実装完了です!

まとめ

以上、「GASのトリガーを月末に設定する方法」について解説しました!

new Date()で生成する日付の扱いは、初心者にとって関門となるポイントです。難しいですが、GASプログラミングをする上では避けては通れないポイントになるので、なんとか克服していきたいですね。

まあ、とにかく練習あるのみです!たくさんコードを書いていればそのうち慣れます。

それではまた次回!

GASを勉強するならこちら!

▼オススメ書籍はこちら!

スポンサーリンク
GASおじさんをフォローする

コメント

タイトルとURLをコピーしました