PostgreSQL 13 min read

PostgreSQLの日付フォーマット ― to_charの書式とto_dateでの変換、MMとMIの取り違え

※この記事にはアフィリエイト広告(プロモーション)が含まれます。

PostgreSQL で日付や時刻を決まった形の文字列にするには to_char(値, '書式') を使います。文字列を日付にするには to_date と to_timestamp を使います。この記事の出力は PostgreSQL 18.6(Ubuntu 26.04 の標準パッケージ)で採りました。

まず見る(結論)

SELECT to_char(now(), 'YYYY-MM-DD HH24:MI:SS');   -- 2026-10-04 15:07:09
SELECT to_char(now(), 'YYYY/MM/DD');              -- 2026/10/04
SELECT to_char(now(), 'YYYYMMDDHH24MISS');         -- 20261004150709
SELECT to_date('2026/10/04', 'YYYY/MM/DD');        -- 2026-10-04(date 型)
  • 分は MI。MM と書くと月が入る
  • 時は HH24。HH だけだと12時間制
  • 先頭の0を消すなら FM を付ける(FMMM/FMDD → 10/4)
  • MySQL の DATE_FORMAT は無い。%Y-%m-%d は YYYY-MM-DD と書き直す

よく使う書式

例はすべて timestamp '2026-10-04 15:07:09.123456'(日曜日)を変換した結果です。

書式 意味 結果
YYYY / YY 年(4桁 / 2桁) 2026 / 26
MM 月(2桁) 10
DD 日(2桁) 04
HH24 時(24時間制) 15
HH / HH12 時(12時間制) 03
AM / PM 午前・午後 PM
MI 分 07
SS 秒 09
MS / US ミリ秒 / マイクロ秒 123 / 123456
Dy / Day 曜日(英語の略称 / 英語) Sun / Sunday
D / ID 曜日の番号(日曜=1 / ISO で月曜=1) 1 / 7
Q 四半期 4
IW ISO 週番号 40
DDD 年の何日目 277
TZ / OF タイムゾーン名 / UTC からの差(timestamptz のみ) JST / +09

MM と MI、HH と HH24 の取り違え

SELECT to_char(timestamp '2026-10-04 15:07:09', 'YYYY-MM-DD HH:MI:SS')   AS hh,
       to_char(timestamp '2026-10-04 15:07:09', 'YYYY-MM-DD HH24:MM:SS') AS mm_wrong;
         hh          |      mm_wrong
---------------------+---------------------
 2026-10-04 03:07:09 | 2026-10-04 15:10:09

どちらもエラーにならずに値が返るので、テストで気づかないことがあります。HH は午後3時を 03 にし、分の位置に MM と書くと月の 10 が入ります。

ゼロ埋めを外す・日本語を入れる

SELECT to_char(timestamp '2026-10-04 15:07:09', 'MM/DD')       AS pad,
       to_char(timestamp '2026-10-04 15:07:09', 'FMMM/FMDD')   AS nopad,
       to_char(timestamp '2026-10-04 15:07:09', 'FMMM月FMDD日') AS ja;
  pad  | nopad |   ja
-------+-------+---------
 10/04 | 10/4  | 10月4日

FM は直後の1項目だけに効きます。月と日の両方の0を消すなら、それぞれに付けます。

書式として意味を持たない文字(年、/、- など)はそのまま出ます。'YYYY年MM月DD日' と 'YYYY"年"MM"月"DD"日"' はどちらも 2026年10月04日 でした。英字を文字として入れたいときは二重引用符で囲みます。'YYYY-"Q"Q' は 2026-Q4 です。囲まないと Q が四半期の番号に置き換わります。

曜日を日本語で出す

TMDay と lc_time の組み合わせで日本語にする方法もありますが、OS に日本語ロケールが入っていないと使えません。この検証機(Ubuntu のクラウドイメージ)では SET lc_time = 'ja_JP.UTF-8'; が invalid value for parameter "lc_time" で失敗しました。

環境に左右されないのは、曜日の番号(extract(dow ...)、日曜=0)を配列で引く方法です。

SELECT (array['日','月','火','水','木','金','土'])[extract(dow from date '2026-10-04') + 1] AS youbi;
 youbi
-------
 日

timestamptz はタイムゾーンで結果が変わる

SET timezone = 'UTC';
SELECT to_char(timestamptz '2026-10-04 15:07:09+09', 'YYYY-MM-DD HH24:MI:SS TZ OF');
 2026-10-04 06:07:09 UTC +00

SET timezone = 'Asia/Tokyo';
SELECT to_char(timestamptz '2026-10-04 15:07:09+09', 'YYYY-MM-DD HH24:MI:SS TZ OF');
 2026-10-04 15:07:09 JST +09

timestamptz の値は、セッションの timezone の時刻に直してから書式に当てはめます。同じ値でも、接続しているアプリの設定によって出る日付が変わります。now() も timestamptz です。timestamp と timestamptz の違いは timestamptz の記事にまとめています。

文字列を日付にする

SELECT to_date('2026/10/04', 'YYYY/MM/DD')                AS a,
       to_date('20261004', 'YYYYMMDD')                    AS b,
       to_timestamp('2026-10-04 15:07', 'YYYY-MM-DD HH24:MI') AS c;
     a      |     b      |           c
------------+------------+------------------------
 2026-10-04 | 2026-10-04 | 2026-10-04 15:07:00+09

to_timestamp が返すのは timestamptz で、セッションのタイムゾーンの時刻として解釈されます。

2026-10-04・2026/10/04・20261004 のような形なら、書式を書かずに '2026/10/04'::date や CAST('2026-10-04' AS date) でも変換できました。10/04/2026 のように月と日の順が読み方で変わる入力は、to_date で書式を明示します。

存在しない日付はどちらの方法でもエラーです。

SELECT to_date('2026-02-30', 'YYYY-MM-DD');
ERROR:  date/time field value out of range: "2026-02-30"

一方、区切り文字の違いは見逃されます。to_date('2026-10-04', 'YYYY/MM/DD') は書式が / なのに - の入力を受け付け、2026-10-04 を返しました。入力の形をそろえたいなら、変換の前に正規表現などで確かめます。

年・月だけを取り出す・月初と月末

SELECT extract(year from date '2026-10-04') AS y,
       extract(month from date '2026-10-04') AS m;
  y   | m
------+----
 2026 | 10

SELECT date_trunc('month', timestamp '2026-10-04 15:07:09') AS month_start,
       (date_trunc('month', date '2026-10-04') + interval '1 month - 1 day')::date AS month_end;
     month_start     | month_end
---------------------+------------
 2026-10-01 00:00:00 | 2026-10-31

extract は文字列ではなく numeric を返すので、計算や比較にそのまま使えます。月ごとに集計するなら GROUP BY date_trunc('month', 列) にします。

MySQL・Oracle から来たときのエラー

書いたもの エラー PostgreSQL での書き方
DATE_FORMAT(now(), '%Y-%m-%d') function date_format(timestamp with time zone, unknown) does not exist to_char(now(), 'YYYY-MM-DD')
to_char(sysdate, ...) column "sysdate" does not exist to_char(now(), ...)
to_char('2026-10-04', 'YYYY/MM/DD') function to_char(unknown, unknown) is not unique to_char('2026-10-04'::date, 'YYYY/MM/DD')

3つ目は、引用符で囲んだ値の型が決まらないために起きます。::date や ::timestamp で型を付けます。

数値の書式

to_char は数値にも使えます。

SELECT to_char(1234567, 'FM9,999,999') AS a,
       to_char(12.5, 'FM990.00')       AS b,
       to_char(12345678, 'FM9,999')    AS overflow;
     a     |   b   | overflow
-----------+-------+----------
 1,234,567 | 12.50 | #,###

9 は桁がなければ何も出さず、0 は 0 で埋めます。桁が足りないとエラーにならずに # が並ぶので、書式の桁数は想定する最大値に合わせます。

関連: PostgreSQLのtimestamptzとは / PostgreSQLにNVLは無い

PostgreSQL をもっと深く知るための本

PostgreSQL実践入門 ──アーキテクチャ、運用監視、性能改善

技術評論社・2026年2月

アーキテクチャから運用監視・性能改善までを扱う。付録に PostgreSQL 18 の新機能と設定項目の差分がある。

Amazonで見る

[改訂3版]内部構造から学ぶPostgreSQL ―設計・運用計画の鉄則

技術評論社・2022年11月・PostgreSQL 14 ベース

内部構造の理解から、設計と運用計画の立て方を学ぶ。

Amazonで見る

Amazonのアソシエイトとして、FIRE SE は適格販売により収入を得ています。