フランスの小規模チームで運用している障害管理ツールで、日付境界のレポートが1日ずれる現象が出た。環境はPostgreSQL 14、アプリはPython 3.11、コンテナはDebianベースでTZ=Europe/Parisを設定していた。データ量は障害チケット約12万件、日次集計は約3年分。現象は「前日23時台に起票したチケットが翌日の集計に入る」というもので、月次レポートの件数が現場の感覚と合わなかった。
まずDBのカラムを確認した。created_atはtimestamp without time zoneで、アプリ側が現地時刻をそのまま入れていた。ここをtimestamp with time zoneに変えると既存データの解釈が変わるため、移行はせず、書き込みをUTCに統一した。
ALTER TABLE incidents
ALTER COLUMN created_at TYPE timestamptz
USING created_at AT TIME ZONE 'Europe/Paris';
アプリ側は保存をUTC、表示をEurope/Parisに分離した。集計はDBで行い、日付境界は明示的にパリ時間で切る。
SELECT date_trunc('day', created_at AT TIME ZONE 'Europe/Paris') AS day,
count(*)
FROM incidents
WHERE created_at >= now() - interval '90 days'
GROUP BY 1
ORDER BY 1;
この形にした理由は、夏時間でUTCとの差が+1時間と+2時間に変わるため、アプリ側で固定オフセットを持たせると年2回必ずずれるからだ。DBにタイムゾーン名を渡せばPostgreSQLが変換する。代償は、集計クエリがインデックスを使いにくくなる点で、12万件では問題ないが数百万件になると範囲条件の書き方を見直す必要がある。
失效するのは、外部から受け取るCSVにタイムゾーン情報がない場合だ。以前、フランスの取引先から届いた日時列をそのままパリ時間とみなして取り込み、実際はUTCだったため1時間ずれた。境界条件として、日付だけの列は時刻を補完しないとUTC変換できない。また、コンテナのTZ設定に依存したコードが残っていると、ローカル実行と本番で結果が変わる。自分はここで一度、テストだけ通る状態を作ってしまった。
日付境界の集計は、どのタイムゾーンで切るかを仕様として決めないと、実装が先に進むほど直しにくくなる。そちらでは、外部データのタイムゾーンが不明なとき、取り込み時点でどのように確認していますか。
0 条评论
还没有评论,写下第一条。