PCでコーディングしたプログラムをAWSのLambda関数で実行したら、datetime.now()
で取得される時刻が異なることに気づきました。PCはJST時間、AWSはUTC時間のため9時間の差があることが原因です。
プログラムを変えずにPCでもAWSのLambda関数でも同じ結果を得るために、datetimeにタイムゾーンを指定する方法を調べました。
#環境
- Python 3.7.4
#問題の事象
例えば次のプログラムを実行すると、PCで取得される現在時刻と、AWSのLambda関数で取得される現在時刻に9時間の差異が発生します。9時間の差異なので、Lambda関数で実行するときには + timedelta(hours=+9)
として9時間足せばいいのだけれど、それではPCからLambda関数に持っていくときにプログラムの修正が発生するので望ましくないため、プログラムを変更せずに同じ結果が得られるようにしたいと考えました。
from datetime import datetime, timezone, timedelta
def lambda_handler(event, context):
print(datetime.now())
#PCとAWSのLambda関数で取得される時刻に9時間の差異が発生
return
if __name__ == "__main__":
event = None
context = None
lambda_handler(event, context)
#解決策
datetimeにタイムゾーンを指定することで解決できます。Python3では標準ライブラリのdatetime
だけで解決できます。具体的には、datetime
オブジェクトを生成する際にtimezone
を指定します。
ただし、timezone
もtimezone
サブクラスから生成する必要があるため、そこでちょっと戸惑いました。
timezone = "Asia/Tokyo"
とかではないということです。
「Pythonでは、すべてがオブジェクト」とかたまに見かけますが、こういうことなんですかね。
JST = timezone(timedelta(hours=+9)) #timezoneの生成
print(datetime.now(JST)) #タイムゾーンを指定して現在時刻を取得
#注意点
datetime
オブジェクトを使った引き算、足し算をしている場合は、タイムゾーンを揃えておかないとTypeError
が発生します。
TypeError: can't subtract offset-naive and offset-aware datetimes
こんな感じにすればOK
JST = timezone(timedelta(hours=+9)) #timezoneの生成
datetime.datetime(2020, 1, 31, tzinfo=JST) - datetime.datetime.now(JST)
#tzinfoにタイムゾーンを設定
#もうひとつの解決策
ここまで調べた後で、もう一つの解決策があることを発見しました。
AWSのLambda関数の環境変数を変更する方法です。いろんなやり方があるのですね。
AWSのLambdaのタイムゾーンをUTCからJST(東京)に変更
なお、
Python3のdatetimeはタイムゾーンを指定するだけで高速になる
そうです。
#「awareなdatetime」と「nativeなdatetime」
datetimeを調べる過程で、「awareなdatetime」や「nativeなdatetime」という言葉が出てきて「なんのこっちゃ」と戸惑いましたが、大まかには、
-
datetime
オブジェクトにタイムゾーンを指定する方法は、「awareなdatetime」 - 実行環境(PC、AWSのLambda関数)のタイムゾーンを合わせる方法は、「nativeなdatetime」
ということみたいです。
言葉だけだと少々理解しにくいですが、実際にプログラムを動かしてみて結果の差異を見ることで実感できました。