例えば、航空券予約アプリを作ってるとしよう。フライトはニューヨーク現地時間で10:00に出発して、ロンドン現地時間で22:00に到着する。でもタイムゾーンを無視すると、サーバーが到着時間をめちゃくちゃに表示しちゃうかも。
タイムゾーンは、君の一番の味方(でも、うまくいかない時は最悪の敵)。ユーザーがいろんな国にいたり、現地時間に依存するスケジュール(例えばフライト時間やイベントの予定)を扱うなら、タイムゾーンの考慮は超重要だよ。
時間データ型の種類
すでに話したけど、タイムスタンプを扱うデータ型は2つある:
TIMESTAMP: 日付と時間(タイムゾーンなし)。TIMESTAMPTZ: 日付と時間(タイムゾーンあり)。
もう一度、例で見てみよう。
-- 2つのカラム(TIMESTAMPとTIMESTAMPTZ)でテーブルを作成
CREATE TABLE flight_schedule (
flight_id SERIAL PRIMARY KEY,
departure_time TIMESTAMP,
departure_time_with_tz TIMESTAMPTZ
);
-- データを挿入
INSERT INTO flight_schedule (departure_time, departure_time_with_tz)
VALUES
('2023-10-25 10:00:00', '2023-10-25 10:00:00+00');
-- データを確認
SELECT * FROM flight_schedule;
結果はサーバーのタイムゾーンによって変わるよ。例えば:
| flight_id | departure_time | departure_time_with_tz |
|---|---|---|
| 1 | 2023-10-25 10:00:00 | 2023-10-25 10:00:00+00 |
ポイントはここ:
departure_timeカラムは、単に日付と時間をタイムゾーンなしで保存してるだけ。departure_time_with_tzカラムは、日付と時間にタイムゾーン情報(この場合は+00)も一緒に保存してる。
時間を別のタイムゾーンに変換する
PostgreSQLでタイムゾーンを扱うには、AT TIME ZONE関数を使うよ。
UTCからローカル時間への変換
例えば、UTC(協定世界時)形式のタイムスタンプがあるとしよう。これをAmerica/New_Yorkタイムゾーンのユーザー向けに表示したい場合:
SELECT
'2023-10-25 14:00:00+00'::TIMESTAMPTZ AT TIME ZONE 'America/New_York' AS local_time;
結果:
| local_time |
|---|
| 2023-10-25 10:00:00 |
AT TIME ZONEはまるで魔法みたいに、UTCから指定したタイムゾーンに時間を変換してくれる。
ローカル時間からUTCへの変換
今度は逆に、America/New_Yorkの時間をUTCに変換したい場合:
SELECT
'2023-10-25 10:00:00'::TIMESTAMP AT TIME ZONE 'America/New_York' AS utc_time;
結果:
| utc_time |
|---|
| 2023-10-25 14:00:00+00 |
結果はTIMESTAMPTZ形式になるよ。なぜならタイムゾーン(この場合はUTC)情報も含まれるから。
TIMESTAMPTZデータ型の扱い
TIMESTAMPTZを使うと、PostgreSQLはサーバーのタイムゾーン(または自分で指定したもの)を自動的に考慮してくれる。
現在のセッションのタイムゾーンを設定するには、次のコマンドを使う:
SET TIMEZONE = 'Europe/Istanbul';
これ以降、TIMESTAMPTZを使った操作はこのタイムゾーンで行われるよ。
例:データの挿入と取得
-- タイムゾーンを設定
SET TIMEZONE = 'Europe/Istanbul';
-- データを挿入
INSERT INTO flight_schedule (departure_time_with_tz)
VALUES ('2023-10-25 10:00:00+00');
-- データを確認
SELECT departure_time_with_tz FROM flight_schedule;
Europe/Istanbulタイムゾーンでの結果:
| departure_time_with_tz |
|---|
| 2023-10-25 13:00:00+03 |
PostgreSQLは指定したタイムゾーンを考慮して、UTCから自動的に時間を変換してくれる。
実践例
スケジュールのタイムゾーン考慮。 例えば、フライトスケジュールのテーブルがあって、各レコードはUTCで出発時間を保存してるとしよう。各フライトの出発時間をローカル時間で表示したい場合:
SELECT
flight_id,
departure_time_with_tz AT TIME ZONE 'America/New_York' AS local_time
FROM flight_schedule;
異なるタイムゾーンの時間データの比較。 例えば、別々の都市で起きた2つのイベントを比較したい場合。PostgreSQLは自動的に同じタイムゾーンに揃えて比較してくれるよ。
SELECT
'2023-10-25 10:00:00+03'::TIMESTAMPTZ > '2023-10-25 07:00:00+00'::TIMESTAMPTZ AS event_one_later;
結果:
| event_one_later |
|---|
| t |
比較結果はtrue。なぜなら10:00+03は07:00+00と同じだから。
コツとよくある落とし穴
時間を扱うのは本当にややこしい。よくあるミスはこんな感じ:
TIMESTAMPをTIMESTAMPTZの代わりに使って、「なんで時間が合わないの?」ってなる(タイムゾーンが無視されてるから)。- サーバーがどのタイムゾーンで動いてるか知らずに、データを挿入した時間と取得した時間がズレる。
AT TIME ZONEでタイムゾーン名を間違えて、エラーや変な時間になる。
こうならないために:
- ほとんどの場合、
TIMESTAMPTZを使おう。特にタイムゾーンに依存するデータなら必須。 - 時間はUTCで保存して、表示時にユーザーのタイムゾーンに変換しよう。
- もっと詳しく知りたいなら、PostgreSQL公式ドキュメント(時間とタイムゾーン)が超便利だよ。
GO TO FULL VERSION