タイムゾーンが設定値と異なる
PostgreSQL側でタイムゾーンをAsia/Tokyoで指定したのに、InteliJのようなJetBrains製のエディターから接続した時にUTCに変わってしまうことがありました。参照するだけであればそこまで問題ではないですが、そこから現在時刻を挿入するようなことがあれば想定と異なるデータになるため問題になります。
このまま使うのが怖かったので調べたところ、InteliJでタイムゾーンを明示的に指定する方法を見つけたので調査結果と解決策についてまとめます。
前提知識と準備
PostgresSQLのタイムゾーン
PostgresSQLのタイムゾーンはpostgresql.confに設定します。
timezone = 'Asia/Tokyo'
※AWSのRDSではクラウドパラメータという機能を使って設定することができるので別の設定方法があります。
下記のクエリを投げると現在のタイムゾーンを確認できます。
show timezone;
クエリでタイムゾーンを変更する方法
クエリでデータベース単位で変更する方法です。検証で使うので先に書いておきます。
ALTER DATABASE DB_NAME SET timezone TO 'Asia/Tokyo'
セッション単位で変更する時(接続を切れば元に戻る)
SET timezone TO 'Asia/Tokyo'
タイムゾーンがAsia/TokyoなPostgreSQLを立ち上げる
ローカルにPostgreSQLのdockerコンテナを立てます。
version: "3"
services:
postgres:
image: postgres:9.6
container_name: "postgres_practice"
ports:
- 5432:5432
environment:
- POSTGRES_USER=postgres_practice
- POSTGRES_PASSWORD=postgres_practice
- POSTGRES_DB=practice
user: root
立ち上げます。
docker-compose up
タイムゾーンを確認するとUTCになっています。
docker exec -it postgres_practice psql -U postgres_practice -W -d practice -c "show timezone"
Password for user postgres_practice:
TimeZone
----------
UTC
(1 row)
デフォルトではUTCになっているのでAsia/Tokyoに変更します。
docker exec -it postgres_practice sed -i 's/UTC/Asia\/Tokyo/g' /var/lib/postgresql/data/postgresql.conf
再起動します。
docker-compose restart
これでタイムゾーンがAsia/TokyoなPostgreSQLが立ち上がります。
docker exec -it postgres_practice psql -U postgres_practice -W -d practice -c "show timezone" 2824ms 月 4/15 02:37:48 2019
Password for user postgres_practice:
TimeZone
------------
Asia/Tokyo
(1 row)
JetBrains製のEditorで確認
しっかりAsia/TokyoなPostgresが立ち上がったところで、JetBrains製のエディターで確認してみます。
下記のような設定で接続します。
タイムゾーンを確認。
なんでやねん。
しっかりUTCで上書きされてました。
データベース単位でタイムゾーン変更クエリを流してみます。
ALTER DATABASE practice SET timezone TO 'Asia/Tokyo'
SHOW timezone
変化なし。
次はセッション単位で変更してみます。
SET timezone TO 'Asia/Tokyo';
SHOW timezone
変わりました。ただしこれは再接続するとまたUTCに戻ります。
つまりセッション単位で何かしらエディター側で設定が上書きされていることがわかります。
でも毎回打つのはいやです。
linuxのタイムゾーンを変えてみる
コンテナの中のタイムゾーンを変えたら変化があるかもしれないと思って試してみました。
現在値の確認。
docker exec -it postgres_practice ls -l /etc/localtime 月 4/15 02:56:35 2019
lrwxrwxrwx 1 root root 27 Mar 26 12:00 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
更新。
docker exec -it postgres_practice ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
確認。
docker exec -it postgres_practice date
Mon Apr 15 02:57:25 JST 2019
変わらない...
下記コマンドを実施して効果なし。
docker exec -it postgres_practice /bin/bash
root:/# echo "Asia/Tokyo" > /etc/timezone
root:/# dpkg-reconfigure -f noninteractive tzdata
Current default time zone: 'Asia/Tokyo'
Local time is now: Mon Apr 15 03:02:37 JST 2019.
Universal Time is now: Sun Apr 14 18:02:37 UTC 2019.
接続時にオプションを指定する
DataGripのFAQにこんな記述がありました。
DataGrip shows time in local time zone, I want it to be shown in UTC, what should I do?
Go to Advanced tab of datasource and put -Duser.timezone=UTC into VM options field.
local time zoneになってしまうから明示的にオプションでタイムゾーンを指定しろと書いてます。
上記の手順で変わらない理由はよくわかりませんが試してみます。
まとめ
調査した結果、タイムゾーンを指定するためには
-
SET timezone TO 'Asia/Tokyo'
を実行する - オプションで指定する
の2パターンあることがわかりました。
エディターで指定することで設定後は意識することなくAsia/Tokyoで接続できるようになるので、この対応をしておくと基本的には安心だと思います。
具体的な原因は分かり次第追記しようと思います。