はじめに
日時情報を扱う中で、タイムゾーンを持たない日時データ(naive)をタイムゾーン付きの日時データ(aware)に変換する場面は少なくありません。
本記事では、その際にastimezone()を使用するときの注意点についてまとめました。
結論を最初に述べると、タイムゾーンを持たない日時オブジェクトに対してastimezone()を使用すると、実行環境によって時刻ズレが発生してしまうため、単にタイムゾーン情報を付与したい場合はreplace()を使おうという話です。
この記事では、
- なぜ時刻ズレが発生するのか
- どう実装すべきか
を、実装例を挙げて説明します。
前提知識: naiveとawareとは
datetimeオブジェクトは、タイムゾーン情報を含むかどうかによってnaiveとawareの2種類に分類されます。
- naive object: タイムゾーン情報を持たないオブジェクト
- aware object: タイムゾーン情報を持つオブジェクト
問題が起きるコード
例えば次のタイムゾーン時間を持たない文字列の日時データを扱うケースを考えます。
2026-03-03 12:00:00
この値を日本時間の2026-03-03 12:00として扱うために、以下の問題があるサンプルコードを用意しました。
from datetime import datetime
from zoneinfo import ZoneInfo
JST = ZoneInfo("Asia/Tokyo")
dt = datetime.strptime("2026-03-03 12:00:00", "%Y-%m-%d %H:%M:%S")
astimezone_result = dt.astimezone(tz=JST)
print(f"出力結果: {astimezone_result.isoformat()}")
実際に実行してみる
ローカルで実行した場合
ローカルでは問題無く日本時間の2026-03-03 12:00になっていますね。
サーバー環境(例:AWS Lambda)上で実行した場合
実装コード
出力結果
9時間ずれて2026-03-03 21:00になってしまっていますね。
なぜastimezone()だとズレるのか
astimezone()の処理として、naiveのオブジェクトをローカルタイムとして解釈してから指定されたタイムゾーンに変換されます。
そのため、多くのサーバー環境(例: AWS Lambda)はローカルタイムがUTCのため、内部的に次のように解釈され変換後に時間がズレるというわけです。
12:00(ローカルタイムからUTCとして解釈)
↓
21:00(+9時間をしてUTCからJSTに変換)
正しい実装例
naiveなdatetimeにJSTのタイムゾーン情報を付与する方法の例としてreplaceメソッドがあります。
今回の問題のあるコードを以下のようにreplaceメソッドで日本時間のタイムゾーンを持たせるようにしました。
from datetime import datetime
from zoneinfo import ZoneInfo
JST = ZoneInfo("Asia/Tokyo")
dt = datetime.strptime("2026-03-03 12:00:00", "%Y-%m-%d %H:%M:%S")
replace_result = dt.replace(tzinfo=JST)
print(f"出力結果: {replace_result.isoformat()}")
実際に実行してみる
replaceだと無事時間がズレることなくJSTのタイムゾーン情報を付与することができました!
公式ドキュメント参考
Python公式ドキュメントのdatetime.astimezoneの説明にも以下のように日時を変更せずに単にタイムゾーンを付与したい場合はreplace(tzinfo=tz)を使用するよう明記されています。
If you merely want to attach a timezone object tz to a datetime dt without adjustment of date and time data, use dt.replace(tzinfo=tz).
まとめ
本記事では、私自身がastimezone()を使用した際に想定外の挙動に遭遇した経験をもとに、naiveとawareの違いおよびastimezone()の仕様について整理しました。
同様の実装をされている方、これから実装を予定している方の参考になれば幸いです。
最後までお読みいただきありがとうございました。
参考




