🕗
タイムゾーン運用の個人的ベストプラクティス
概要
Webアプリケーションを開発する際、タイムゾーンの取り扱いに悩んだことはありませんか?
本記事では、Webアプリケーションにおける「タイムゾーン運用」の個人的なベストプラクティスをまとめます。
サンプルコードの技術スタック
- 言語: TypeScript
- データベース: PostgreSQL
【統一方針】
timestamptz
」型 + UTC で統一
🕒 DBは「created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc', now());
-
timestamptz
は内部では UTC で保存 -
timestamp
はタイムゾーン情報を持たず、セッションTZに依存するため非推奨
【APIの入出力】
⬇️ 入力 (POST / PUT)
- ユーザーがローカルで入力した日時 (JST など)を
UTC ISO形式 (toISOString)に変換してAPIに送信
const local = new Date('2025-08-08T15:00:00')
const utc = local.toISOString() // "2025-08-08T06:00:00.000Z"
⬆️ 出力 (GET)
- APIは UTCのISO8601文字列 (例:
2025-08-08T06:00:00Z
) を返す
【表示の際にローカルに直す】
- 表示の階層でのみ、ユーザーTZ (例: Asia/Tokyo) に変換
-
dayjs
,date-fns-tz
などが便利
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)
const jst = dayjs.utc('2025-08-08T06:00:00Z').tz('Asia/Tokyo').format('YYYY/MM/DD HH:mm')
timestamp
vs timestamptz
の違いと落とし穴
❌ timestampはセッションTZに依存
-
timestamp
は「そのままの時刻」を保存 - どのTZからの時刻なのか分からないため、表示や比較でずれる
- Supabase は基本的に全セッション UTC で動作
【SET TIME ZONE について】
-- 一時的に JST の時刻表示にしたい場合
SET TIME ZONE 'Asia/Tokyo';
- これは「セッション内だけの表示TZ」に影響
- DB内の時刻は変わらない
【まとめ】
階層 | 定義 |
---|---|
DB |
timestamptz + UTC で統一 |
API入力 | UTC ISO文字列で送る |
API出力 | UTC ISO文字列で返す |
表示 | ユーザーTZに変換して表示 |
DB検索/比較 | UTCのままではっきり関数を使える |
👉 すべてのデータを UTC で扱い、表示だけローカルのタイムゾーンにするという方針が基本です。
Discussion