※この記事にはアフィリエイト広告(プロモーション)が含まれます。
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 で埋めます。桁が足りないとエラーにならずに # が並ぶので、書式の桁数は想定する最大値に合わせます。