SHOW timezoneで分かるのはOSのタイムゾーンじゃない

  • PostgreSQL
  • SQL

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

PostgreSQLで「今のタイムゾーンどうなってるっけ」と確認したいとき、SHOW timezone; を叩く人が多いと思う。これで表示されるのはあくまでその時点のセッションでのTimeZoneパラメータの最終結果で、どこでその値に決まったのかまでは教えてくれない。実際にタイムゾーンを確認するには、この最終結果だけじゃなく決定過程も追う必要がある。

結論

SHOW timezone; で分かるのは「今このクエリを実行しているセッションでの実効値」だけ。

SHOW timezone;

これはPostgreSQLの実行時パラメータ TimeZone の現在値を返している。値そのものは正しいが、その値がサーバー起動時のデフォルトなのか、データベース単位の設定なのか、それとも接続時に個別にセットされたものなのかは、このクエリ単体では判別できない。

優先順位を押さえる

TimeZone パラメータは複数の階層で設定でき、後勝ちで上書きされる。

1. サーバー起動時のデフォルト(OSの TZ / PGTZ 環境変数由来)
2. postgresql.conf の timezone 設定
3. ALTER DATABASE dbname SET timezone TO '...'(データベース単位)
4. ALTER ROLE rolename SET timezone TO '...'(ロール単位)
5. SET timezone = '...'(セッション単位、接続後の明示的な変更)

つまり SHOW timezone; が返す値は、この5段階を全部積み重ねた結果の最終値でしかない。どこかで意図しない上書きが入っていても、この一発のクエリからは見分けがつかない。

上書きの有無を確認する

データベース単位・ロール単位の上書きが入っていないかは別クエリで見に行く必要がある。

-- データベース単位の上書き
SELECT datname, datconfig
FROM pg_database
WHERE datname = current_database();
-- ロール単位の上書き
SELECT rolname, rolconfig
FROM pg_roles
WHERE rolname = current_user;

datconfig や rolconfig の中に timezone=... という項目が入っていれば、それが SHOW timezone; の結果に反映されている上書きの正体。何も入っていなければ、サーバーのデフォルト設定(postgresql.conf かOSの環境変数由来)がそのまま使われていることになる。

タイムゾーン名を確認する

SHOW timezone; で返ってくる値が正しいタイムゾーン名かどうか、あるいは別の名前に切り替えたいときは pg_timezone_names ビューを使う。IANAのタイムゾーンデータベースをそのまま使っているので、他のミドルウェアで見慣れた名前がそのまま通じる。

SELECT name, utc_offset, is_dst
FROM pg_timezone_names
WHERE name = 'Asia/Tokyo';

まとめて確認する

結局、PostgreSQLのタイムゾーンを正確に把握したいなら、SHOW timezone; だけでなく上書きの有無もセットで見るのが確実。

SHOW timezone;
SELECT datconfig FROM pg_database WHERE datname = current_database();
SELECT rolconfig FROM pg_roles WHERE rolname = current_user;

この3本を実行すれば、実効値とその出どころの両方が分かる。