Posted at

PostgreSQLでtimestamp without time zone型のカラムの値をJSTに変換する

More than 1 year has passed since last update.

PostgreSQLのバージョンは9.6, DBのタイムゾーンはUTCとします。


結論

users.created_at のような timestamp without time zone 型のカラムがある場合、次のようにするとJSTの時刻を取得できます。

timezone('JST', users.created_at::timestamptz)

まず、timestamp without time zone 型のカラムである users.created_at の値を timestamp with time zone 型の略記である timestamptz 型にキャストしています。::PostgreSQLにおける型キャストの記法です。そして、タイムゾーン変換の構文 timestamp AT TIME ZONE zone と等価である timezone 関数でJSTに変換しています。


正しくない例

次のようにするとできません。

timezone('JST', users.created_at)

この場合、 users.created_at2018-08-10 00:00:00 だと timezone('JST', users.created_at)2018-08-09 15:00:00 となり、UTCの2018-08-10 00:00:00におけるJSTの時間を期待して9時間進んでほしいところが、9時間戻ってしまいます。

これは、JSTとして users.created_at を解釈したあとに、ローカル時間(この場合UTC)の時間はいつか、というロジックで値を表示するからです。つまり、この場合 2018-08-10 02:46:58 をJSTとして解釈し、それはUTCでは 2018-08-09 17:46:58 である、というふうになっています。これは timestamp without time zone 型の値に対する timezone 関数は「与えられた時間帯なしタイムスタンプを指定された時間帯にあるとして取り扱う」という仕様によります。

そこで、users.created_attimestamp with time zone 型にキャストします。すると、この場合は timezone 関数が「与えられた時間帯付きタイムスタンプを新規の時間帯に、時間帯の指定なく変換する」という仕様になります。これによって、JSTへ変換したタイムスタンプを表示することができます。


参考