背景
AWS Lambda処理内で、RDSのデータを読み書きする機能を開発していました。
プログラム上で日時を生成してテーブルに格納するのですが、実行環境(ローカル or AWS Lambda)によって日時の値が異なってしまっていました。
環境・前提
- Java8
- Eclipse(2020-12 M3)
- RDS(MySQL 8.0)
- AWS Lambda
ローカルで開発中は Eclipse で JUnit を実行し、ローカルから RDS の読み書きを行います。
AWS Lambda へプログラムのデプロイ後は、AWS Lambda を実行し、 RDS の読み書きを行います。
検証
① ローカル(Eclipse)から、RDSへ
プログラム上の日時(UTC)1 | RDS上の日時 |
---|---|
2021/3/25 12:00:00 | 2021/3/25 3:00:00 |
この場合、RDSへ登録された時点でソース上の日時から -9:00
の日時へと自動変換されてしまう。
② AWS Lambdaから、RDSへ
プログラム上の日時(UTC) | RDS上の日時 |
---|---|
2021/3/25 12:00:00 | 2021/3/25 12:00:00 |
この場合、日時の値変更は発生しない。
原因
AWS Lambda と RDS のデフォルトのタイムゾーンが UTC
であることと、以下2点のタイムゾーンの仕様を認知していなかったため、値の差異が発生していました。
MySQLのタイムゾーン
接続先/接続元のタイムゾーンが異なる場合、絶対時刻のカラム(Timestamp型)であれば、自動で日時が変換されます(検証①のパターン)。
11.2.2 The DATE, DATETIME, and TIMESTAMP Types
ローカル実行環境のタイムゾーン
JRE の場合、標準では OS のレジストリや環境変数から、デフォルトのタイムゾーンを判別するようです。
今回、私の環境では実行環境のタイムゾーンが Asia/Tokyo
となっていました。
対処方法
対処方法としては以下のように何通りかあります。
- AWS Lambda の環境変数設定
- MySQL のタイムゾーン設定
- ローカル実行環境のタイムゾーン設定
今回は AWS Lambda の設定が複雑化したり、MySQLの設定を変更することを避けたかったため、
3. のローカル実行環境のタイムゾーンを指定する方法を採用します。
手段
ローカル実行環境のタイムゾーンを指定する方法も、下記のようにいくつかあります。
- 環境変数
JAVA_OPTIONS
に-Duser.timezone=UTC
を設定 - プログラム単位で、
実行の構成 -> VM引数
に-Duser.timezone=UTC
を設定 - ワークスペース単位で、
インストール済みのJRE -> デフォルトのVM引数
に
-Duser.timezone=UTC
を設定
今回は3つ目、「ワークスペース単位での指定」を行います。
設定手順:デフォルトVM引数の設定
備考
AWS Lambda や、 RDS のタイムゾーンを日本基準にする方法もありましたが、どちらもデフォルトのタイムゾーンが UTC
だったので、プログラム側も UTC
に寄せました。
AWS Lambda の環境変数を設定する方法はお手軽そうでした。
しかし、開発で増えゆくはずの Lambda 関数に一つ一つ環境変数を設定するのは手間だなぁというのと、
自由度が低くなりそうだなぁということで、不採用としました。
-
Timestamp.valueOf(LocalDateTime.now(ZoneId.of("UTC")))
で生成した日時 ↩