🌴

[Redshift]勝手にサマータイム?

2023/04/17に公開約2,200字

RedshiftでCONVERT_TIMEZONE関数を用いてUTC(協定世界時)から日本時間へ変換する処理を実装しています。

ある日、ユーザーからの問い合わせをきっかけに、UTCから日本時間へ正しく変換されていないことが発覚しました。

UTC+10

CONVERT_TIMEZONEの構文は下記の通りです。

CONVERT_TIMEZONE( ['source_timezone',] 'target_timezone', 'timestamp')

これを参考に、UTCのtimestampカラムを日本時間へ変換するべく、下記のような使い方をしていました。

SELECT CONVERT_TIMEZONE('UTC', 'Asia/Tokyo', 'timestamp') FROM hogehoge;

日本時間はUTC+9のため、UTCから9時間進んだ値が出力されたらOKです。
しかし、なぜか10時間進んだ値が出力されていたのです…。

サマータイム適用説

公式ドキュメントを改めて確認すると、気になる記述が…

タイムゾーン名の使用
タイムゾーン名を使用してタイムゾーンを指定する場合、CONVERT_TIMEZONE は自動的に夏時間 (DST)、または 'timestamp' によって指定される日付と時刻で有効なその他の現地の季節の慣習 (サマータイム、標準時、冬時間) を調整します。例えば、'Europe/London' は冬季は UTC を表し、夏季は 1 時間を追加します。

タイムゾーンの略名の使用
タイムゾーンの略名は、UTC からの固定オフセットを表します。タイムゾーンの略名を使用してタイムゾーンを指定する場合、CONVERT_TIMEZONE は UTC からの固定オフセットを使用し、現地の季節の慣習を調整しません。

サマータイムが導入されていない日本は無関係だと思っていたのですが、もしやと思い、タイムゾーン名(Asia/Tokyo)をタイムゾーンの略名(JST)に修正してみました。

SELECT CONVERT_TIMEZONE('UTC', 'JST', 'timestamp') FROM hogehoge;

上記を実行すると…ビンゴでした!UTCから9時間進んだ値が出力されました。

つまり、元のクエリはサマータイムだと判定されてUTC+9(日本時間)+1(サマータイム)=10時間進んだ値が出力されていた可能性が高そうです。

深まる謎

日次でCONVERT_TIMEZONEを用いた処理を実行しているテーブルの過去データを確認してみました。
2023年4月13日(日本時間)実行分からUTC+10の値になっており、それ以前はUTC+9の値でした。

サマータイム適用国について軽く調査したのですが、2023年4月13日からサマータイムを適用している国は無さそうでして…謎です。

私の知らない間に日本はサマータイムを導入していたのかもしれません(?)

結論

RedshiftでCONVERT_TIMEZONE使用する際はタイムゾーンの略名を用いた方が安全です!

余談:Snowflakeでは

念のためSnowflakeでも確認してみました。
Snowflakeでも

SELECT CONVERT_TIMEZONE('UTC', 'Asia/Tokyo', 'timestamp') FROM hogehoge;

という書き方が可能ですが、問題なくUTC+9時間で変換されることを確認しました。

ちなみに、Snowflakeの公式ドキュメント

Snowflakeは、タイムゾーンの 略語 の大半を サポートしていません (例: PDT、 EST)。特定の略語は、いくつかの異なるタイムゾーンの1つを参照している可能性があるためです。たとえば、 CST は、北米の中部標準時(UTC-6)、キューバ標準時(UTC-5)、および中国標準時(UTC+8)を指す場合があります。

と記載があるように、タイムゾーンの略名を殆どサポートしていません。

Snowflakeでは下記のようにタイムゾーン名(Asia/Tokyo)をタイムゾーンの略名(JST)に変更して実行するとエラーになりますので、ご注意下さい。

SELECT CONVERT_TIMEZONE('UTC', 'JST', 'timestamp') FROM hogehoge; -- NG

RedshiftのクエリをSnowflakeに移行する際は気にする必要がありますね。

Discussion

ログインするとコメントできます