CloudWatch Eventsのルールで日本時刻の月末(0時~9時)が指定できない時の対処法

CloudWatch Eventsのルールでは日本時刻の月末(0時~9時)に処理を実行するというスケジュールが指定できない、という質問に対処法を回答しました。
2020.12.28

困っていたこと

「日本時間(JST)の毎月末の午前5:00に処理を実行する」というCloudWatchのEventsルールをCron式で設定することは可能でしょうか?

月末という指定があるため、CloudWatch Eventsルールのワイルドカードを使用して設定しようと考えておりますが、UTC時刻が基準のため月末を指定したときに午前5:00を指定できない認識です。

月末の0時から9時は月末を指定するワイルドカード(L)を使用する必要がありますが、それではUTCの時刻の月末となってしまいます。

そのため、JSTとの時差を考慮してUTCである9時間前を指定しようとすると、月末1日前という指定になってしまうため、月末のワイルドカードが使用できません。

どう対応すればいいの?

今回の場合、「日本時間(JST)の毎月末の午前5:00に処理を実行する」必要があるため、月末1日前の20時に発火するCloudWatch Eventsルールを作成する必要があります。

しかし、CloudWatch EventsルールのCron式で使えるものに月末1日前を指定できるものはないため、CloudWatch Eventsの機能のみでは実装はできません。

そのため、CloudWatch Events をトリガーとして Lambda 関数を経由して行いたい処理を実行する方法が考えられます。

今回の場合は以下の条件でCloudWatch EventsとLambdaを作成する必要があります。

  1. CloudWatch Events の Cron 式には 28 - 31 日の 20:00 UTC (JSTで翌日の5:00 )に起動するように設定する
  2. CloudWatch Events のターゲットとして Lambda 関数を設定いただき、Lambda 関数内で月末の判定を行う
  3. Lambda 関数による判定の結果、月末である場合に処理を実行する

やってみた

Lambda関数の作成

今回は実行日時を取得して、その日時が月末であるかどうかを判定する必要があります。

サンプルですがpython3.7で以下のようなLambda関数を作成してみました。あくまでサンプルなので、細かい部分はいい感じに編集してください。

実行日の日付とその月の月末を取得し、実行日が月末と同じ日だった場合に処理を実行します。

from datetime import datetime, timedelta, timezone,date
from dateutil.relativedelta import relativedelta

def is_first_day():
    isFirstDay = False
    JST = timezone(timedelta(hours=+9), 'JST')
    # 日本時刻で今日の日付を取得
    todayJST=datetime.now(JST).date()
    # その月の月末日付を取得
    lastDay = (todayJST + relativedelta(months=1)).replace(day=1) - timedelta(days=1)
    if todayJST == lastDay :
        isFirstDay = True
    return isFirstDay

def lambda_handler(event, context):
    isFirstDay = is_first_day()
    if isFirstDay == True :
        # 月末に行いたい処理を書く
        print('今日は月末です')
    else:
        print('今日は月末ではありません')

printで文字列を出力している部分は、適宜実行したい処理や返したいメッセージに書き換えてください。

CloudWatch Eventsのルール作成

Cron式で28日から31日の20:00 UTC を指定するため、以下をスケジュールに設定します。

0 20 28-31 * ? *

ターゲットには先ほど作成したLambda関数を指定しましょう。

設定の詳細からルールの名前と説明を入力して作成すれば設定は完了です。

これで「日本時間(JST)の毎月末の午前5:00に処理を実行する」ことができるようになりました。