twtjudy1128
@twtjudy1128 (Juri Tawata)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

GASで契約終了日が今日から30日以内だったらSlackに通知が来るようにしたい

解決したいこと

GASでスプレッドシートの特定の列から日付(契約終了日)を抽出して、
契約終了日が今日から30日以内だったらSlackに通知が行くようにしたいです。

目的は、契約終了日1ヶ月前に、営業が漏れなくアプローチできるようにするためです。

発生している問題・エラー

エラーは出ていないのですが、以下のようなコードにすると、
今日より前の日付、すなわち契約終了してしまっているものまで抽出されてしまいます。

function alertContract() {
    var mySheet = SpreadsheetApp.openById('sheetid').getSheetByName('シート1'); //スプレッドシートを取得
    var lastRow = mySheet.getLastRow(); //スプレッドシートの最終行を取得
    var today = new Date(); //今日の日付を取得

    /* 契約終了日まで30日以内だったらSlack投稿 */
    for (var i = 5; i <= lastRow; i++) {
       var Di = mySheet.getRange(i, 4).getValue(); //企業名(Di列)を取得
        var dateAAi = new Date(mySheet.getRange(i, 27).getValue()); //契約終了予定日(AAi列)を取得
        var period = dateAAi.getDate() - today.getDate(); //今日から契約終了予定日までの期間を取得
      if (period <= 30) { //終了30日前の企業に通知
          //通知文を作成
          var strText = "@XXX " + Di + "様の契約終了日が迫っています。必ずアプローチしましょう。期限:" + dateAAi;
          //Slackへ投稿
          postSlack(strText);
        }

    }
}

自分で試したこと

以下のように、if文の中の条件を
if (period <= 30)から
if (period >= 0 && period <= 30)に変更してみました。

function alertContract() {
    var mySheet = SpreadsheetApp.openById('sheetid').getSheetByName('シート1'); //スプレッドシートを取得
    var lastRow = mySheet.getLastRow(); //スプレッドシートの最終行を取得
    var today = new Date(); //今日の日付を取得

    /* 契約終了日まで0~30日だったらSlack投稿 */
    for (var i = 5; i <= lastRow; i++) {
       var Di = mySheet.getRange(i, 4).getValue(); //企業名(Di列)を取得
        var dateAAi = new Date(mySheet.getRange(i, 27).getValue()); //契約終了予定日(AAi列)を取得
        var period = dateAAi.getDate() - today.getDate(); //今日から契約終了予定日までの期間を取得
      if (period >= 0 && period <= 30) { //終了30日前の企業に通知
          //通知文を作成
          var strText = "@XXX " + Di + "様の契約終了日が迫っています。必ずアプローチしましょう。期限:" + dateAAi;
          //Slackへ投稿
          postSlack(strText);
        }

    }
}

すると、トリガーでエラーは出ていないのですが、Slackに全く通知が来なくなってしまいました。
該当する案件があるので、データがないというわけではありません。

エラーが出ていないため、原因がつかめずにおります。

どなたかご教示いただけますと幸いです。

よろしくお願いします。

1

1Answer

結論

以下の通りで動くことを確認しました(テストケース少なめなので、境界値でちゃんと動くかはご自身でお願いします)。

...
var period = Math.ceil((dateAAi - today) / (1000 * 60 * 60 * 24));
if (period >= 0 && period <= 30) { //終了30日前の企業に通知
...

解説

まずご質問を見る限り、if文の判定は問題ない気がしました。
なのでperiodに入ってくる値がそもそも正しくないのでは?と考えます。

Logger.log(period);

を入れて実行後、表示→ログ(MacならCmd+Enter)でログで値の確認ができます。
2020-10-01のような未来の日付を入れて実行したら、本来3が返ってくるはずが、-27.0という結果が返ってきました。未来なのにマイナスなのが明らかにおかしいですね。

よく見ると.getDate()で減算をしていますが、getDateは年月日の日が返ってきます。
なので(2020年10月1日)-(2020年9月28日)ではなく、1-28=-27という計算がされます。
そのため、月をまたぐと結果が正しく返ってこないことが分かります。

修正

日付の差を出した後、結果がミリ秒で返ってくるので1000で割って秒、60で割って分、60で割って時、24で割って日数、更に繰上げをして日付に変換すれば、正しく日付の差が出せます。

余談

今回の内容と関係ないですが、getRange().getValue()は実行ごとにスプレッドシートと通信が走ります。
そのため件数が多いと実行時間がかかりすぎて、件数次第ではタイムアウトの可能性があります。
getRangeで一括で範囲指定し、getValuesで全て取ってきた後にループを回すと、スプレッドシートとの通信が1回で済むので実行時間が短くなります。

リファクタリングの際にご活用ください。

5Like

Comments

  1. @twtjudy1128

    Questioner

    返信が遅くなりました。。。ご回答頂き、誠にありがとうございます!無事に修正することができ、作りたいものを完成させることができました!本当にありがとうございます!

    リファクタリングというワードも知らなかったのですが、調べて勉強になりました!そこも改善できるようにやってみようと思います!

    ありがとうございます(^-^)
  2. お役に立てたようで何よりです。
    うまく動かない時は、原因を推測してそれを一つ一つ検証することが解決の糸口になるので、今後も頑張ってください。

Your answer might help someone💌