PHPのdate関数とは、date('Y-m-d H:i:s') のようにフォーマット文字を並べて、日付や時刻を好きな形の文字列にする関数です。 同じフォーマット文字は DateTime や DateTimeImmutable の format() メソッドでもそのまま使えます。

この記事では、フォーマット文字の全一覧を実際の出力例つきでまとめ、「2026年3月7日」「2026/03/07 09:05」のようなよく使う書式の逆引き表を用意しました。後半では、1月31日 に +1 month を足すと3月になる月末の動きを再現し、回避するコードを紹介します。日数差、曜日の日本語表示、和暦、タイムゾーン変換まで、すべて PHP 8.4.21 で実行した結果を載せています。

date関数フォーマットの早見表

まずは、最もよく使う書式の逆引きです。出力例は 2026-03-07 09:05:03(土曜日、タイムゾーンは Asia/Tokyo)を整形した結果です。

欲しい形 フォーマット 出力例
年-月-日 Y-m-d 2026-03-07
年/月/日 Y/m/d 2026/03/07
日本語(ゼロなし) Y年n月j日 2026年3月7日
日本語(ゼロあり・時刻つき) Y年m月d日 H時i分s秒 2026年03月07日 09時05分03秒
日時(DBのDATETIME型と同じ形) Y-m-d H:i:s 2026-03-07 09:05:03
日時(秒なし) Y/m/d H:i 2026/03/07 09:05
時刻だけ H:i 09:05
12時間表記 g:i A 9:05 AM
区切りなし(ファイル名向け) Ymd / YmdHis 20260307 / 20260307090503
年月だけ Y-m 2026-03
月初の日付 Y-m-01 2026-03-01
月末の日付 Y-m-t 2026-03-31
ISO 8601(APIのやり取り向け) c または Y-m-d\TH:i:sP 2026-03-07T09:05:03+09:00
ミリ秒つき Y-m-d H:i:s.v 2026-03-07 09:05:03.123
英語表記 l, F jS, Y Saturday, March 7th, 2026
短い和式 y.n.j 26.3.7
UNIXタイムスタンプ U 1772841903
ISO週番号つき o-\WW-N 2026-W10-6

使い方は2通りあり、どちらも同じフォーマット文字を使います。

書き方 コード 向いている場面
関数 date('Y-m-d') / date('Y-m-d', $timestamp) 現在日時をさっと表示する
クラス (new DateTimeImmutable('2026-03-07'))->format('Y-m-d') 日付の計算・比較・タイムゾーン変換を行う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP date関数フォーマット一覧|DateTimeでの日付計算も解説」

動作確認した環境とコードの前提

出力はすべて次の環境で実行した結果です。

項目 内容
PHP 8.4.21(CLI)
intl拡張 有効(ICU 74.2)
タイムゾーン コードの先頭で Asia/Tokyo を指定

この記事のコードは、先頭に次の1行がある前提です。タイムゾーンを指定しないと、サーバーの設定(今回の環境では UTC)で表示され、日本時間と9時間ずれます。

<?php
date_default_timezone_set('Asia/Tokyo');

フォーマット文字の全一覧

2026-03-07 09:05:03.123456(土曜日)を1文字ずつ整形した出力です。大文字と小文字で意味が変わるので、表で確認しながら使ってください。

<?php
date_default_timezone_set('Asia/Tokyo');
$dt = new DateTimeImmutable('2026-03-07 09:05:03.123456');
foreach (str_split('dDjlNSwzWFmMntLoXxYyaABgGhHisuveIOPpTZcrU') as $c) {
    echo $c, "\t", $dt->format($c), PHP_EOL;
}

日

文字 意味 出力例
d 日(2桁、ゼロあり) 07
j 日(ゼロなし) 7
D 曜日(英語3文字) Sat
l(小文字のエル) 曜日(英語フルスペル) Saturday
N 曜日の番号(月曜=1 〜 日曜=7) 6
w 曜日の番号(日曜=0 〜 土曜=6) 6
S 日の英語の接尾辞(st, nd, rd, th) th
z 年の初めからの日数(0始まり) 65

週・月

文字 意味 出力例
W ISO 8601 の週番号 10
F 月(英語フルスペル) March
M 月(英語3文字) Mar
m 月(2桁、ゼロあり) 03
n 月(ゼロなし) 3
t その月の日数 31

年

文字 意味 出力例
Y 年(4桁) 2026
y 年(下2桁) 26
L うるう年なら 1、そうでなければ 0 0
o ISO 8601 の週番号に対応する年 2026
X 符号つきの拡張表記の年(PHP 8.2以降) +2026
x 可能なら符号なしの拡張表記の年(PHP 8.2以降) 2026

時・分・秒

文字 意味 出力例
H 時(24時間、2桁) 09
G 時(24時間、ゼロなし) 9
h 時(12時間、2桁) 09
g 時(12時間、ゼロなし) 9
i 分(2桁) 05
s 秒(2桁) 03
a 午前・午後(小文字) am
A 午前・午後(大文字) AM
v ミリ秒(3桁) 123
u マイクロ秒(6桁) 123456
B スウォッチ・インターネットタイム 045

date() 関数は整数のタイムスタンプを受け取るため、date('u') は常に 000000、date('v') は常に 000 になりました。ミリ秒やマイクロ秒が必要なときは DateTimeImmutable を使います。

タイムゾーン・全体

文字 意味 出力例
e タイムゾーン名 Asia/Tokyo
T タイムゾーンの略称 JST
P UTCとの差(コロンあり) +09:00
p P と同じ。ただし +00:00 のとき Z(PHP 8.0以降) +09:00
O UTCとの差(コロンなし) +0900
Z UTCとの差(秒) 32400
I(大文字のアイ) サマータイム中なら 1 0
c ISO 8601 形式の日時 2026-03-07T09:05:03+09:00
r RFC 2822 形式の日時 Sat, 07 Mar 2026 09:05:03 +0900
U UNIXタイムスタンプ(秒) 1772841903

間違えやすい組み合わせ

迷う文字 違い
m と i m は月、i は分。H:m:s と書くと「時:月:秒」になる
d と j d は 07、j は 7
m と n m は 03、n は 3
M と F M は Mar、F は March
D と l D は Sat、l は Saturday
H と h H は24時間、h は12時間
Y と o 年末年始の数日だけ値が異なることがある。通常の年表示は Y
w と N w は日曜が 0、N は日曜が 7

フォーマット文字をそのまま表示したいとき

フォーマット文字として解釈されたくない英字は、前に \ を付けます。日本語の文字はフォーマット文字ではないので、そのまま書けます。

echo $dt->format('\T\o\d\a\y \i\s l'), PHP_EOL;
echo $dt->format('Y年n月j日'), PHP_EOL;
Today is Saturday
2026年3月7日

定義済みの書式定数

よく使われる規格の書式は、定数として用意されています。

定数 出力例
DateTimeInterface::ATOM 2026-03-07T09:05:03+09:00
DateTimeInterface::RFC3339 2026-03-07T09:05:03+09:00
DateTimeInterface::RFC3339_EXTENDED 2026-03-07T09:05:03.123+09:00
DateTimeInterface::ISO8601 2026-03-07T09:05:03+0900
DateTimeInterface::RFC2822 Sat, 07 Mar 2026 09:05:03 +0900
DateTimeInterface::COOKIE Saturday, 07-Mar-2026 09:05:03 JST
DateTimeInterface::RSS Sat, 07 Mar 2026 09:05:03 +0900

JSONのAPIで日時をやり取りするときは DateTimeInterface::ATOM(または c)を使うと、タイムゾーンの差まで含んだ形になります。

date・strtotime・mktimeの基本

関数だけで日付を扱うときは、次の3つを組み合わせます。

関数 役割 例 結果
time() 現在のUNIXタイムスタンプ time() 整数(秒)
date($format, $ts) タイムスタンプを文字列にする date('Y-m-d', 0) 1970-01-01(日本時間では 09:00:00)
strtotime($文字列, $基準) 文字列をタイムスタンプにする strtotime('2026-10-02 +1 week') 2026-10-09 のタイムスタンプ
mktime(時, 分, 秒, 月, 日, 年) 数値からタイムスタンプを作る mktime(0, 0, 0, 3, 7, 2026) 2026-03-07 のタイムスタンプ
checkdate(月, 日, 年) 存在する日付かを確かめる checkdate(2, 29, 2026) false
echo date('Y-m-d H:i:s', 0), PHP_EOL;
echo date('Y-m-d', strtotime('2026-10-02 +1 week')), PHP_EOL;
var_dump(strtotime('abc'));
1970-01-01 09:00:00
2026-10-09
bool(false)

strtotime() は読み取れない文字列に対して false を返します。 そのまま date() に渡すと false は 0 として扱われ、1970年1月1日が表示されます。画面に「1970/01/01」が出たときは、strtotime() の戻り値を確認すると原因が見つかります。

strtotimeで使える相対表現の一覧

基準を 2026-10-02 10:00:00(金曜日)にして、date('Y-m-d H:i:s (D)', strtotime($表現, $基準)) を実行した結果です。

表現 結果
now 2026-10-02 10:00:00 (Fri)
today 2026-10-02 00:00:00 (Fri)
tomorrow 2026-10-03 00:00:00 (Sat)
yesterday 2026-10-01 00:00:00 (Thu)
+1 day 2026-10-03 10:00:00 (Sat)
-3 days 2026-09-29 10:00:00 (Tue)
+1 week 2026-10-09 10:00:00 (Fri)
+1 month 2026-11-02 10:00:00 (Mon)
-1 year 2025-10-02 10:00:00 (Thu)
+2 hours 30 minutes 2026-10-02 12:30:00 (Fri)
next monday 2026-10-05 00:00:00 (Mon)
last friday 2026-09-25 00:00:00 (Fri)
friday(当日が金曜) 2026-10-02 00:00:00 (Fri)
next friday 2026-10-09 00:00:00 (Fri)
monday this week 2026-09-28 00:00:00 (Mon)
sunday this week 2026-10-04 00:00:00 (Sun)
first day of this month 2026-10-01 10:00:00 (Thu)
last day of this month 2026-10-31 10:00:00 (Sat)
first day of next month 2026-11-01 10:00:00 (Sun)
last day of next month 2026-11-30 10:00:00 (Mon)
last day of previous month 2026-09-30 10:00:00 (Wed)
first monday of next month 2026-11-02 00:00:00 (Mon)
last friday of this month 2026-10-30 00:00:00 (Fri)
first day of january this year 2026-01-01 00:00:00 (Thu)
midnight / noon 2026-10-02 00:00:00 / 12:00:00
tomorrow noon 2026-10-03 12:00:00 (Sat)

表から読み取れるポイントは2つです。today や曜日名を指定すると時刻が 00:00:00 になり、+1 day や first day of は元の時刻(10:00:00)を保ちます。 また、tomorrow と +1 day は時刻の扱いが異なります。

存在しない日付は繰り上がる

echo date('Y-m-d', strtotime('2026-02-30')), PHP_EOL;
echo date('Y-m-d', mktime(0, 0, 0, 13, 1, 2026)), PHP_EOL;
echo date('Y-m-d', mktime(0, 0, 0, 3, 0, 2026)), PHP_EOL;
var_dump(checkdate(2, 29, 2026), checkdate(2, 29, 2028), checkdate(13, 1, 2026));
2026-03-02
2027-01-01
2026-02-28
bool(false)
bool(true)
bool(false)

2月30日 は 3月2日、13月 は翌年の 1月 に繰り上がります。3月0日 が 2月28日 になる性質は、月末日を求める方法としても使われます。入力された日付が実在するかを確かめたいときは checkdate() を使います。

DateTimeとDateTimeImmutableの使い方

日付の計算や比較には、クラスを使うと読みやすく書けます。関数との対応は次のとおりです。

やりたいこと 関数での書き方 クラスでの書き方
現在日時 time() new DateTimeImmutable()
文字列から作る strtotime('2026-10-02') new DateTimeImmutable('2026-10-02')
数値から作る mktime(0,0,0,10,2,2026) (new DateTimeImmutable())->setDate(2026,10,2)->setTime(0,0)
書式を指定して読み取る (なし) DateTimeImmutable::createFromFormat('Y/m/d', '2026/10/02')
整形する date('Y-m-d', $ts) $dt->format('Y-m-d')
足す・引く strtotime('+1 day', $ts) $dt->modify('+1 day') / $dt->add(new DateInterval('P1D'))
差を求める ($ts2 - $ts1) / 86400 $dt1->diff($dt2)->days
比較する $ts1 < $ts2 $dt1 < $dt2
タイムスタンプを得る そのまま $dt->getTimestamp()
タイムゾーンを変える date_default_timezone_set() $dt->setTimezone(new DateTimeZone('UTC'))

DateTimeは元の値が変わる

DateTime と DateTimeImmutable の違いは、計算したときに元のオブジェクトが変わるかどうかです。

// DateTime(ミュータブル=変更できる)
$start = new DateTime('2026-10-02');
$end   = $start->modify('+7 days');
echo $start->format('Y-m-d'), ' / ', $end->format('Y-m-d'), PHP_EOL;
var_dump($start === $end);

// DateTimeImmutable(イミュータブル=変更されない)
$start = new DateTimeImmutable('2026-10-02');
$end   = $start->modify('+7 days');
echo $start->format('Y-m-d'), ' / ', $end->format('Y-m-d'), PHP_EOL;
2026-10-09 / 2026-10-09
bool(true)
2026-10-02 / 2026-10-09

DateTime では、開始日のつもりだった $start まで7日後に変わりました。$start と $end は同じオブジェクトを指しています。DateTimeImmutable は計算のたびに新しいオブジェクトを返すので、元の値はそのまま残ります。

クラス modify() などの動き 使いどころ
DateTime 自分自身を書き換える 既存のコードに合わせる場合。コピーが必要なら clone する
DateTimeImmutable 新しいオブジェクトを返す 新しく書くコードはこちらがおすすめ

DateTime を使い続ける場合は、clone でコピーしてから計算します。

$s2 = new DateTime('2026-10-02');
$e2 = (clone $s2)->modify('+7 days');
echo $s2->format('Y-m-d'), ' / ', $e2->format('Y-m-d'), PHP_EOL;
2026-10-02 / 2026-10-09

一方、DateTimeImmutable では戻り値を受け取る必要があります。受け取らないと何も変わりません。

$im = new DateTimeImmutable('2026-10-02');
$im->modify('+1 day');           // 戻り値を受け取っていない
echo $im->format('Y-m-d'), PHP_EOL;
2026-10-02

足し算・引き算

$d = new DateTimeImmutable('2026-10-02');
echo $d->add(new DateInterval('P1Y2M10DT2H30M'))->format('Y-m-d H:i'), PHP_EOL;
echo $d->sub(new DateInterval('P10D'))->format('Y-m-d'), PHP_EOL;
echo $d->setDate(2027, 1, 15)->format('Y-m-d'), PHP_EOL;
echo (new DateTimeImmutable('2026-10-02 15:30'))->setTime(0, 0)->format('Y-m-d H:i'), PHP_EOL;
2027-12-12 02:30
2026-09-22
2027-01-15
2026-10-02 00:00

DateInterval の書式は P(期間)で始め、時刻の部分は T で区切ります。

書き方 意味
P1D 1日
P2W 2週間
P1M 1か月
P1Y 1年
PT1H 1時間
PT30M 30分(T のあとの M は分)
P1Y2M10DT2H30M 1年2か月10日と2時間30分

月末問題:1月31日に+1 monthで3月になる

日付計算で最もつまずきやすいのが、月末日に「1か月」を足す場面です。

$d = new DateTimeImmutable('2026-01-31');
echo $d->modify('+1 month')->format('Y-m-d'), PHP_EOL;
echo date('Y-m-d', strtotime('2026-01-31 +1 month')), PHP_EOL;
echo $d->add(new DateInterval('P1M'))->format('Y-m-d'), PHP_EOL;
2026-03-03
2026-03-03
2026-03-03

3つの書き方すべてで、2月ではなく3月3日になりました。 PHPは「月の数字を1つ増やす」→「2月31日」→「存在しないので繰り上げる(2月は28日までなので3日分あふれて3月3日)」という順で計算するためです。ほかの日付でも確かめました。

元の日付 操作 結果 理由
2026-01-31 +1 month 2026-03-03 2月31日 → 3日あふれる
2024-01-31(うるう年) +1 month 2024-03-02 2月31日 → 2日あふれる
2026-03-31 -1 month 2026-03-03 2月31日 → 3月3日(月が戻らない)
2026-05-31 +1 month 2026-07-01 6月31日 → 7月1日
2024-02-29 +1 year 2025-03-01 2025年2月29日 → 3月1日

DateTime で1月31日から +1 month を繰り返すと、最初の1回で3日にずれたあと、そのまま毎月3日になりました。

03-03 04-03 05-03 06-03

回避方法1:first day of / last day of を使う

「翌月の月初」「翌月の月末」が欲しいだけなら、first day of と last day of を使うと月がずれません。

$d = new DateTimeImmutable('2026-01-31');
echo $d->modify('first day of next month')->format('Y-m-d'), PHP_EOL;
echo $d->modify('last day of next month')->format('Y-m-d'), PHP_EOL;
2026-02-01
2026-02-28

関数でも同じ表現が使えます。

$ts = strtotime('2026-01-31');
echo date('Y-m-d', strtotime('first day of next month', $ts)), PHP_EOL;
echo date('Y-m-d', strtotime('last day of next month', $ts)), PHP_EOL;
2026-02-01
2026-02-28

「来月」「先月」という月単位の集計では、先に first day of で1日にそろえてから月を動かすと覚えておくと安心です。

回避方法2:月末に収まるように足す関数を用意する

「毎月同じ日。ただしその日がない月は月末」という動きにしたいときは、次の関数が使えます。

function addMonths(DateTimeImmutable $date, int $months): DateTimeImmutable
{
    $day   = (int)$date->format('j');
    $first = $date->modify('first day of this month')
                  ->modify(($months >= 0 ? '+' : '') . $months . ' month');
    $last  = (int)$first->format('t');   // 移動先の月の日数

    return $first->setDate((int)$first->format('Y'), (int)$first->format('n'), min($day, $last));
}

foreach ([['2026-01-31', 1], ['2026-01-31', 2], ['2026-03-31', -1], ['2024-01-31', 1],
          ['2026-10-15', 3], ['2026-11-30', 3], ['2026-12-31', 2]] as [$s, $m]) {
    echo "$s $m => ", addMonths(new DateTimeImmutable($s), $m)->format('Y-m-d'), PHP_EOL;
}
2026-01-31 1 => 2026-02-28
2026-01-31 2 => 2026-03-31
2026-03-31 -1 => 2026-02-28
2024-01-31 1 => 2024-02-29
2026-10-15 3 => 2027-01-15
2026-11-30 3 => 2027-02-28
2026-12-31 2 => 2027-02-28

ポイントは、常に「最初の基準日」から月数を数えることです。前回の結果に1か月ずつ足していくと、2月で28日になったあと3月も28日になってしまうため、addMonths($基準日, 1)、addMonths($基準日, 2) のように基準日からの月数で求めます。

月末日を求める方法

方法 コード 2026年2月の結果
フォーマット文字 t date('t', strtotime('2026-02-01')) 28
Y-m-t (new DateTimeImmutable('2026-02-10'))->format('Y-m-t') 2026-02-28
last day of ->modify('last day of this month')->format('Y-m-d') 2026-02-28

うるう年の2028年2月では、date('t', strtotime('2028-02-01')) は 29 を返しました。

日数差・期間を求める

2つの日付の差は diff() で求めます。戻り値は DateInterval オブジェクトです。

$a = new DateTimeImmutable('2026-10-02');
$b = new DateTimeImmutable('2026-12-25');

$i = $a->diff($b);
echo $i->days, ' / ', $i->format('%mか月%d日'), ' / ', $i->format('%R%a日'), ' / invert=', $i->invert, PHP_EOL;

$i = $b->diff($a);          // 逆向き
echo $i->days, ' ', $i->format('%R%a'), ' invert=', $i->invert, PHP_EOL;
84 / 2か月23日 / +84日 / invert=0
84 -84 invert=1

通算の日数は days、月と日に分けた「残りの日数」は d です。 この2つは別の値なので、取り違えないようにしましょう。

プロパティ・書式 意味 上の例での値
$i->days / %a 通算の日数 84
$i->y / %y 年の部分 0
$i->m / %m 月の部分 2
$i->d / %d 日の部分(月を除いた残り) 23
$i->h / %h、$i->i / %i 時・分の部分 0
$i->invert / %R 逆向きなら 1 / 符号(+ -) 0 / +

年齢・経過時間・比較

// 年齢(誕生日の前日なので、まだ36歳になっていない)
$birth = new DateTimeImmutable('1990-10-03');
echo '年齢: ', $birth->diff(new DateTimeImmutable('2026-10-02'))->y, PHP_EOL;

// 経過時間
$i = (new DateTimeImmutable('2026-10-02 09:00'))->diff(new DateTimeImmutable('2026-10-03 18:30'));
echo $i->format('%a日 %h時間 %i分'), PHP_EOL;

// 比較は演算子でそのまま書ける
var_dump($a < $b, $a == new DateTimeImmutable('2026-10-02 00:00:00'));
echo max($a, $b)->format('Y-m-d'), PHP_EOL;
年齢: 35
1日 9時間 30分
bool(true)
bool(true)
2026-12-25

期間内の日付を順に取り出す

DatePeriod を使うと、開始日から終了日の前日までを1日ずつ取り出せます。

$p = new DatePeriod(new DateTimeImmutable('2026-10-01'), new DateInterval('P1D'), new DateTimeImmutable('2026-10-05'));
foreach ($p as $day) {
    echo $day->format('n/j'), ' ';
}
echo PHP_EOL;

// 2026年10月の平日(月〜金)の日数を数える
$c = 0;
foreach (new DatePeriod(new DateTimeImmutable('2026-10-01'), new DateInterval('P1D'), new DateTimeImmutable('2026-11-01')) as $day) {
    if ((int)$day->format('N') < 6) {
        $c++;
    }
}
echo "平日数: $c", PHP_EOL;
10/1 10/2 10/3 10/4 
平日数: 22

終了日そのものは含まれないので、月全体を回すときは終了日に翌月1日を指定します。祝日は含まれないため、必要な場合は祝日の一覧を別に用意して除外します。

今週の月曜日と日曜日

$n  = new DateTimeImmutable('2026-10-02');
$ws = $n->modify('monday this week');
echo $ws->format('Y-m-d'), '〜', $ws->modify('+6 days')->format('Y-m-d'), PHP_EOL;
echo (new DateTimeImmutable('2026-10-04'))->modify('monday this week')->format('Y-m-d'), PHP_EOL;
2026-09-28〜2026-10-04
2026-09-28

monday this week は、日曜日(10月4日)に実行しても同じ週の月曜日(9月28日)を返しました。PHPでは週の始まりが月曜日として扱われます。

曜日を日本語で表示する

date('D') や date('l') は英語で返るため、日本語にするには配列を使う方法と、intl拡張の IntlDateFormatter を使う方法があります。

配列を使う方法(拡張モジュールなしで動く)

$w = ['日', '月', '火', '水', '木', '金', '土'];
$d = new DateTimeImmutable('2026-10-02');
echo $d->format('Y年n月j日') . '(' . $w[(int)$d->format('w')] . ')', PHP_EOL;

$ts = strtotime('2026-10-04');
echo date('n/j', $ts) . '(' . $w[date('w', $ts)] . ')', PHP_EOL;
2026年10月2日(金)
10/4(日)

w は日曜を 0 とする番号なので、配列は「日」から始めます。

IntlDateFormatterを使う方法

$f = new IntlDateFormatter('ja_JP', IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'Asia/Tokyo');
echo $f->format($d), PHP_EOL;

$f = new IntlDateFormatter('ja_JP', IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'Asia/Tokyo', null, 'y年M月d日(E) HH:mm');
echo $f->format(new DateTimeImmutable('2026-10-02 14:05')), PHP_EOL;

$f->setPattern('EEEE');
echo $f->format($d), PHP_EOL;
2026年10月2日金曜日
2026年10月2日(金) 14:05
金曜日

IntlDateFormatter のパターン文字は date() とは別の体系(ICUの書式)で、E が曜日の短い形、EEEE が長い形です。日付・時刻のスタイル定数ごとの出力は次のとおりでした(2026-10-02 14:05:09 を日付・時刻とも同じスタイルで整形)。

スタイル 出力
FULL 2026年10月2日金曜日 14時05分09秒 日本標準時
LONG 2026年10月2日 14:05:09 JST
MEDIUM 2026/10/02 14:05:09
SHORT 2026/10/02 14:05

和暦(令和・平成)で表示する

intl拡張が使える環境では、ロケールに @calendar=japanese を付け、カレンダーに IntlDateFormatter::TRADITIONAL を指定すると和暦で表示できます。

$wa = new IntlDateFormatter(
    'ja_JP@calendar=japanese',
    IntlDateFormatter::FULL,
    IntlDateFormatter::NONE,
    'Asia/Tokyo',
    IntlDateFormatter::TRADITIONAL
);
foreach (['2026-10-02', '2019-04-30', '2019-05-01', '1989-01-07', '1989-01-08'] as $s) {
    echo $s, "\t", $wa->format(new DateTimeImmutable($s)), PHP_EOL;
}
2026-10-02  令和8年10月2日金曜日
2019-04-30  平成31年4月30日火曜日
2019-05-01  令和元年5月1日水曜日
1989-01-07  昭和64年1月7日土曜日
1989-01-08  平成元年1月8日日曜日

元号の切り替わり日(2019年5月1日、1989年1月8日)も正しく判定され、1年目は「元年」と表示されました。パターンを自分で指定する場合は G が元号、y が年です。

$wa2 = new IntlDateFormatter('ja_JP@calendar=japanese', IntlDateFormatter::NONE, IntlDateFormatter::NONE,
    'Asia/Tokyo', IntlDateFormatter::TRADITIONAL, 'Gy年M月d日');
echo $wa2->format(new DateTimeImmutable('2026-10-02')), ' / ', $wa2->format(new DateTimeImmutable('2019-05-01')), PHP_EOL;

$wa2->setPattern('GGGGGy.MM.dd');
echo $wa2->format(new DateTimeImmutable('2026-10-02')), PHP_EOL;
令和8年10月2日 / 令和1年5月1日
R8.10.02

独自パターン Gy年 では1年目が「令和1年」になりました。 「元年」と表示したい場合は、FULL や LONG のスタイルを使います。

intl拡張が使えない環境では、元号の開始日を配列で持つ方法があります。

function wareki(DateTimeInterface $d): string
{
    $eras = [['令和', '2019-05-01'], ['平成', '1989-01-08'], ['昭和', '1926-12-25'],
             ['大正', '1912-07-30'], ['明治', '1868-01-25']];
    foreach ($eras as [$name, $start]) {
        if ($d->format('Y-m-d') >= $start) {
            $y = (int)$d->format('Y') - (int)substr($start, 0, 4) + 1;
            return $name . ($y === 1 ? '元' : $y) . '年' . $d->format('n月j日');
        }
    }
    return $d->format('Y年n月j日');
}

foreach (['2026-10-02', '2019-04-30', '2019-05-01', '1989-01-07'] as $s) {
    echo wareki(new DateTimeImmutable($s)), PHP_EOL;
}
令和8年10月2日
平成31年4月30日
令和元年5月1日
昭和64年1月7日

タイムゾーンの設定と変換

date_default_timezone_setで既定のタイムゾーンを決める

$ts = 1790902800;
echo date('Y-m-d H:i:s T', $ts), PHP_EOL;      // 設定前(この環境の既定は UTC)
date_default_timezone_set('Asia/Tokyo');
echo date('Y-m-d H:i:s T', $ts), PHP_EOL;
2026-10-02 01:00:00 UTC
2026-10-02 10:00:00 JST

同じタイムスタンプでも、表示は9時間違います。タイムスタンプは世界共通の「ある瞬間」を表す数値で、タイムゾーンは「それをどの地域の時計で読むか」の設定です。

設定する場所 書き方 範囲
php.ini date.timezone = Asia/Tokyo サーバー全体
スクリプトの先頭 date_default_timezone_set('Asia/Tokyo'); そのスクリプト
オブジェクトごと new DateTimeImmutable('now', new DateTimeZone('Asia/Tokyo')) そのオブジェクトだけ

タイムゾーン名のつづりが違うと、date_default_timezone_set() は false を返し、次の通知が出ました。設定は変更されません。

PHP Notice:  date_default_timezone_set(): Timezone ID 'Asia/Tokio' is invalid

別のタイムゾーンに変換する

$tokyo = new DateTimeImmutable('2026-10-02 09:00:00', new DateTimeZone('Asia/Tokyo'));
echo $tokyo->format('c'), PHP_EOL;
echo $tokyo->setTimezone(new DateTimeZone('UTC'))->format('c'), PHP_EOL;
echo $tokyo->setTimezone(new DateTimeZone('America/New_York'))->format('Y-m-d H:i T (P)'), PHP_EOL;
echo $tokyo->setTimezone(new DateTimeZone('Europe/London'))->format('Y-m-d H:i T (P)'), PHP_EOL;

var_dump($tokyo->getTimestamp() === $tokyo->setTimezone(new DateTimeZone('UTC'))->getTimestamp());
2026-10-02T09:00:00+09:00
2026-10-02T00:00:00+00:00
2026-10-01 20:00 EDT (-04:00)
2026-10-02 01:00 BST (+01:00)
bool(true)

setTimezone() は表示するタイムゾーンを切り替えるだけで、指している瞬間(タイムスタンプ)は変わりません。 サマータイム(EDT、BST)も自動で反映されています。

UTCで保存された日時を日本時間で表示する例です。

$utc = new DateTimeImmutable('2026-10-01T15:30:00Z');
echo $utc->setTimezone(new DateTimeZone('Asia/Tokyo'))->format('Y-m-d H:i:s'), PHP_EOL;

$fromTs = new DateTimeImmutable('@1790902800');   // @つきはタイムスタンプ。常にUTCになる
echo $fromTs->format('c'), ' -> ', $fromTs->setTimezone(new DateTimeZone('Asia/Tokyo'))->format('c'), PHP_EOL;
2026-10-02 00:30:00
2026-10-02T01:00:00+00:00 -> 2026-10-02T10:00:00+09:00

文字列の末尾に Z や +09:00 があるとき、また @タイムスタンプ で作ったときは、既定のタイムゾーンではなくその指定が使われます。 表示前に setTimezone() で日本時間に切り替えましょう。

文字列を日付として読み取る・検証する

createFromFormatで書式を指定して読み取る

echo DateTimeImmutable::createFromFormat('!Y/m/d', '2026/10/02')->format('Y-m-d H:i:s'), PHP_EOL;
echo DateTimeImmutable::createFromFormat('Y年n月j日 H:i', '2026年10月2日 14:05')->format('c'), PHP_EOL;
var_dump(DateTimeImmutable::createFromFormat('Y-m-d', '2026/10/02'));
2026-10-02 00:00:00
2026-10-02T14:05:00+09:00
bool(false)

書式の先頭に ! を付けると、指定しなかった時刻が 00:00:00 になります。 ! を付けない場合は、時刻に現在の時刻が入ります。書式と文字列が合わないときは false が返ります。

入力された日付が正しいかを確かめる

createFromFormat() も存在しない日付を繰り上げるため、読み取った結果を同じ書式で整形し直し、元の文字列と一致するかで判定します。

function isValidDate(string $s, string $fmt = 'Y-m-d'): bool
{
    $d = DateTimeImmutable::createFromFormat('!' . $fmt, $s);
    return $d !== false && $d->format($fmt) === $s;
}

var_dump(isValidDate('2026-02-28'), isValidDate('2026-02-30'), isValidDate('2026-2-3'), isValidDate('abc'));
bool(true)
bool(false)
bool(false)
bool(false)

読み取れない文字列を渡したとき

try {
    new DateTimeImmutable('abc');
} catch (Throwable $e) {
    echo get_class($e), ': ', $e->getMessage(), PHP_EOL;
}
DateMalformedStringException: Failed to parse time string (abc) at position 0 (a): The timezone could not be found in the database

PHP 8.4 では DateMalformedStringException が投げられました。modify('abc') も同じ例外になります。利用者の入力をそのまま渡す場合は、try〜catch で受けるか、先に isValidDate() のような関数で確かめます。

日付処理のチェックリスト

確認項目 内容
タイムゾーンを指定している php.ini の date.timezone か date_default_timezone_set('Asia/Tokyo')
分は i、月は m H:i:s と Y-m-d
新しいコードは DateTimeImmutable 元の値が変わらない。戻り値を必ず受け取る
月単位の計算は first day of を使う 31日に +1 month すると翌々月になることがある
通算日数は days d は月を除いた残りの日数
strtotime() の戻り値を確認する 読み取れないと false(1970年1月1日と表示される)
入力の検証は checkdate() か整形し直して比較 2月30日は3月2日に繰り上がる
APIや保存にはタイムゾーンつきの形 c や DateTimeInterface::ATOM

よくある質問

Q. date() と DateTime はどちらを使えばよいですか? A. 現在の日時を表示するだけなら date('Y-m-d H:i:s') が手軽です。日付の足し引き、差の計算、タイムゾーンの変換を行う場合は DateTimeImmutable を使うと、元の値が変わらず読みやすく書けます。フォーマット文字はどちらも共通です。

Q. 日付が1970年1月1日と表示されるのはなぜですか? A. date() の第2引数に 0 や false が渡っています。多くは strtotime() が文字列を読み取れずに false を返したケースです。strtotime() の戻り値を var_dump() で確認してみてください。

Q. 時刻が9時間ずれるのはなぜですか? A. PHPの既定のタイムゾーンが UTC になっています。php.ini に date.timezone = Asia/Tokyo を設定するか、スクリプトの先頭で date_default_timezone_set('Asia/Tokyo'); を呼び出します。

Q. 来月の同じ日を求めるにはどうすればよいですか? A. 28日までの日付なら modify('+1 month') でそのまま求められます。29〜31日は翌月にその日がない場合があるので、本文の addMonths() のように「翌月の月末を上限にする」処理を入れます。月初・月末が欲しいだけなら first day of next month・last day of next month が使えます。

まとめ

  • date('Y-m-d H:i:s') が基本形。月は m、分は i、ゼロなしは n・j、月末日は t
  • フォーマット文字は date() と DateTime::format() で共通。ミリ秒 v・マイクロ秒 u はクラスで使う
  • strtotime() は相対表現(+1 week、next monday、last day of this month)を読み取れる。読み取れないときは false
  • DateTime は計算で元の値が変わり、DateTimeImmutable は新しいオブジェクトを返す。新しいコードは後者がおすすめ
  • 1月31日の +1 month は3月3日になる。月単位の計算は first day of・last day of か、月末を上限にする関数で行う
  • 日数差は diff()->days、曜日の日本語は配列か IntlDateFormatter、和暦は ja_JP@calendar=japanese
  • タイムゾーンは最初に設定し、変換は setTimezone() で行う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP date関数フォーマット一覧|DateTimeでの日付計算も解説」

株式会社RJCでは、日付や時刻の扱い方といった基礎を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?