PostgreSQLで前日の日付を出す、Asia/Tokyoなら引き算とタイムゾーン変換の順番は気にしなくていい

  • PostgreSQL
  • SQL
  • Timezone

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

前日の日付を取るクエリを書く機会があったので、やり方を整理した。

やりたいこと

CURRENT_TIMESTAMP(timestamptz型)から前日の日付だけを、Asia/Tokyo基準で取り出す。

クエリ

パターン1: 先にUTCで1日引いてからTokyoに変換

SELECT ((CURRENT_TIMESTAMP - INTERVAL '1 day') AT TIME ZONE 'Asia/Tokyo')::DATE AS yesterday_date;

パターン2: 先にTokyoに変換してから1日引く

SELECT (CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Tokyo' - INTERVAL '1 day')::DATE AS yesterday_date;

結論から言うと、この2つはAsia/Tokyoである限り結果が一致する。

なぜ一致するか

Asia/TokyoはUTC+9固定でDST(サマータイム)を持たない。だから「UTCで1日引いてからローカルに変換」しても「ローカルに変換してから1日引いて」も、時刻がズレる要因がない。

逆にDSTがあるタイムゾーン(America/New_Yorkなど)だと、この2つの順序で結果が食い違うケースがある。日付をまたぐタイミングでDST切り替えが起きると、UTC側で1日引く操作とローカル側で1日引く操作が別の実時刻を指してしまうため。

型の変換方向のメモ

  • timestamptz AT TIME ZONE 'zone' → timestamp(タイムゾーンなしのローカル時刻表現)になる
  • timestamp AT TIME ZONE 'zone' → timestamptzになる

向きが逆になるので、CURRENT_TIMESTAMP(timestamptz)に対して使う場合は前者の変換になる。

より頑健にしたい場合

日付境界を明示したいならdate_truncを使う書き方もある。

SELECT (date_trunc('day', CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Tokyo') - INTERVAL '1 day')::DATE AS yesterday_date;

ただしAsia/Tokyo固定の今回のケースでは、上の2パターンのどちらでも問題なく前日の日付が取れる。DSTのあるタイムゾーンを扱う可能性がある場合は、先にローカルタイムゾーンへ変換してから日付演算する方が意図通りになりやすい。