1. ホーム
  2. PHP

【PHP】date() と DateTime で日付・時刻を扱う方法|フォーマットと計算

Share

PHP で開発をしていると、「今日の日付を表示したい」「投稿日から経過日数を計算したい」「ユーザーが入力した文字列を日付として扱いたい」といった場面が必ず出てきます。PHP には日付・時刻を扱う方法が大きく分けて 2 つあり、手軽に書ける手続き型の date() 系の関数と、計算や比較に強いオブジェクト指向の DateTime クラスがあります。この記事では、両方の基本から、フォーマット文字、加算・減算、差分計算、タイムゾーン、文字列からの変換までを、実際に動くコードで初心者向けに解説します。

PHP で日付を扱う2つのアプローチ

PHP で日付・時刻を扱う方法は、おおまかに次の 2 系統があります。1 つは date()time() などの関数を使う手続き型のやり方、もう 1 つは DateTime クラスを使うオブジェクト指向のやり方です。

手続き型は「現在の日付をサッと文字列で表示したい」といった単純な用途に向いています。一方で「1 か月後を求める」「2 つの日付の差を出す」といった計算を伴う処理では、DateTime クラスを使うほうがコードが読みやすく、間違いも起きにくくなります。まずは手続き型から見ていき、後半でクラスの使い方に進みます。

date() で現在の日付を表示する

もっとも基本的なのが date() 関数です。第 1 引数に「フォーマット文字列」を渡すと、現在の日時をその形式の文字列にして返します。第 2 引数に Unix タイムスタンプ(1970 年 1 月 1 日からの経過秒数)を渡すと、その時刻を整形できます。省略した場合は現在時刻(time() の戻り値)が使われます。

date-basic.php
<?php
// 現在の日時を「年-月-日 時:分:秒」で表示
echo date("Y-m-d H:i:s");
// 例: 2026-06-05 09:19:17

echo "\n";

// 日本語の表記にすることもできる
echo date("Y年n月j日 H時i分");
// 例: 2026年6月5日 09時19分

"Y" は 4 桁の年、"m" は 2 桁の月、"d" は 2 桁の日…というように、1 文字ずつが意味を持つ「フォーマット文字」になっています。フォーマット文字以外の - などはそのまま出力されます。

date() の主なフォーマット文字

date() で使えるフォーマット文字は数多くありますが、まずは下記のよく使うものを押さえておけば十分です。これらは後述する DateTimeformat() でもそのまま使えます。

文字意味出力例
Y4桁の年2026
y2桁の年26
m2桁の月(0埋め)06
n月(0埋めなし)6
d2桁の日(0埋め)05
j日(0埋めなし)5
H24時間表記の時(0埋め)09
G24時間表記の時(0埋めなし)9
i分(0埋め)19
s秒(0埋め)17
D曜日の英語短縮(3文字)Fri
l曜日の英語フルFriday
N曜日番号(月=1〜日=7)5
w曜日番号(日=0〜土=6)5
aam / pm(小文字)am
AAM / PM(大文字)AM
UUnixタイムスタンプ1780964357

注意したいのは、フォーマット文字はあくまで英字 1 文字に意味が割り当てられているという点です。たとえば「Y」のつもりで使った文字が、PHP 側では別の意味を持っていることもあります。もしアルファベットをそのまま文字として出したい場合は、\(バックスラッシュ)でエスケープします。たとえば date("Y\年") のように書くと「年」は曜日番号などと解釈されず、そのまま出力されます。日本語の「年」「月」はフォーマット文字ではないのでエスケープ不要です。

time() / mktime() / strtotime() でタイムスタンプを作る

date() の第 2 引数に渡すタイムスタンプを作る関数も覚えておくと、「特定の日付」を扱えるようになります。

time() は現在時刻のタイムスタンプを返します。mktime() は時・分・秒・月・日・年を指定してタイムスタンプを作る関数です。strtotime() は「2026-06-04」や「+1 day」のような英語の日付表現を解釈してタイムスタンプに変換します。

timestamp.php
<?php
// 現在のタイムスタンプ
$now = time();

// 引数は mktime(時, 分, 秒, 月, 日, 年) の順
$t = mktime(0, 0, 0, 1, 1, 2026);
echo date("Y-m-d", $t);   // 2026-01-01

echo "\n";

// 文字列を解釈してタイムスタンプにする
$ts = strtotime("2026-06-04 10:30:00");
echo date("Y-m-d H:i:s", $ts);   // 2026-06-04 10:30:00

echo "\n";

// 相対的な表現も解釈できる
echo date("Y-m-d", strtotime("+1 week"));   // 1週間後の日付

mktime() の引数が「時・分・秒・月・日・年」という、日本語の感覚とは逆の順番になっている点には注意してください。strtotime() は便利ですが、解釈できる形式とできない形式があり、後述するように思わぬ落とし穴になることもあります。

DateTime クラスの基本

ここからはオブジェクト指向の DateTime クラスを見ていきます。日付の計算や比較を行うなら、こちらのほうが断然おすすめです。new DateTime() のコンストラクタには、日付を表す文字列を渡します。引数を省略すると現在時刻になります。

作成した DateTime オブジェクトは、format() メソッドに先ほどのフォーマット文字を渡すことで文字列に整形できます。

datetime-basic.php
<?php
// 日付を指定して生成
$dt = new DateTime("2026-06-04 10:00:00");

// format() で整形(date() と同じフォーマット文字が使える)
echo $dt->format("Y-m-d H:i:s");   // 2026-06-04 10:00:00

echo "\n";

// 引数を省略すると現在時刻
$now = new DateTime();
echo $now->format("Y年n月j日");

DateTime はオブジェクトなので、後から modify() で日付を変更したり、別の DateTime と比較したりできます。日付を「データとして持ち回る」用途に向いているわけです。

modify() と DateInterval で加算・減算する

「3 日後」「1 か月前」のような計算には 2 つの方法があります。1 つは modify()"+3 day" のような文字列を渡す方法、もう 1 つは DateInterval オブジェクトを作って add()(加算)/ sub()(減算)に渡す方法です。

modify.php
<?php
$dt = new DateTime("2026-06-04 10:00:00");

// modify() で1日進める
$dt->modify("+1 day");
echo $dt->format("Y-m-d");   // 2026-06-05

echo "\n";

// DateInterval で「1か月と10日」進める
// P=期間, 1M=1か月, 10D=10日。時間部分は T のあとに書く
$dt->add(new DateInterval("P1M10D"));
echo $dt->format("Y-m-d");   // 2026-07-15

DateInterval の文字列は ISO 8601 という規格に沿った書き方をします。先頭の P は「Period(期間)」の意味で必須です。Y(年)M(月)D(日)を続けて書き、時・分・秒を指定するときは T を挟みます。たとえば「2 時間 30 分」なら "PT2H30M" です。MT の前なら「月」、後なら「分」を表す点に注意してください。

diff() で2つの日付の差を求める

2 つの日付の差を求めるには diff() メソッドを使います。戻り値は DateInterval オブジェクトで、年・月・日などの差が個別に入っています。経過した総日数を知りたいときは days プロパティが便利です。

diff.php
<?php
$a = new DateTime("2026-06-04");
$b = new DateTime("2026-12-25");

$diff = $a->diff($b);

// 総日数(差を日数だけで表したもの)
echo $diff->days . "日";   // 204日

echo "\n";

// %a は総日数, %m は月, %d は端数の日
echo $diff->format("%a日(%mか月%d日)");   // 204日(6か月21日)

DateInterval::format() のフォーマット文字は date() とは別物で、%a(総日数)、%y(年)、%m(月)、%d(日)、%R(符号)などを使います。%d は「月をまたいだ後の端数の日数」なので、上の例では総日数 204 日が「6 か月と 21 日」に分解されています。単純に「あと何日か」を知りたいときは days プロパティを使うのが確実です。

タイムゾーンを正しく設定する

日付・時刻を扱ううえで避けて通れないのがタイムゾーンです。サーバーの設定によっては UTC(協定世界時)になっていて、日本時間と 9 時間ずれることがあります。これを揃える方法は 2 つあります。

1 つはスクリプト全体の既定タイムゾーンを date_default_timezone_set() で設定する方法です。date()DateTime の既定値がまとめて切り替わります。もう 1 つは、DateTime の生成時に DateTimeZone オブジェクトを渡して、その日付だけタイムゾーンを指定する方法です。

timezone.php
<?php
// スクリプト全体を日本時間に設定(ファイルの先頭で行う)
date_default_timezone_set("Asia/Tokyo");

echo date("Y-m-d H:i:s");   // 日本時間で表示される

echo "\n";

// 特定の DateTime だけタイムゾーンを指定する
$dt = new DateTime("2026-06-04 10:00:00", new DateTimeZone("Asia/Tokyo"));
echo $dt->format("Y-m-d H:i:s P");   // 2026-06-04 10:00:00 +09:00

日本で動かすアプリケーションなら、ほとんどの場合 "Asia/Tokyo" を指定すれば問題ありません。date_default_timezone_set() はスクリプトの一番最初(日付処理を行う前)に呼ぶのがポイントです。なお、php.ini の date.timezone に設定しておけば、コード側で毎回呼ばなくても済みます。

文字列を日付に変換する

フォームの入力値や CSV のデータなど、文字列を日付として扱いたい場面もよくあります。手続き型なら strtotime()、オブジェクト指向なら DateTime::createFromFormat() を使います。

createFromFormat() は「どんな形式の文字列か」を第 1 引数で明示できるのが強みです。strtotime() が解釈しづらい独自フォーマットでも、形式を指定すれば正しく読み取れます。

parse.php
<?php
// strtotime: 一般的な形式なら自動で解釈
$ts = strtotime("2026/06/04 10:30");
echo date("Y-m-d H:i:s", $ts);   // 2026-06-04 10:30:00

echo "\n";

// createFromFormat: 形式を第1引数で指定する
// 第1引数が「文字列の並び方」、第2引数が「解析したい文字列」
$dt = DateTime::createFromFormat("Y/m/d H:i", "2026/06/04 10:30");
echo $dt->format("Y-m-d H:i:s");   // 2026-06-04 10:30:00

createFromFormat() の第 1 引数は format() と同じフォーマット文字で「入力文字列の並び」を表します。たとえば "Y/m/d H:i" は「年/月/日 時:分」という並びの文字列を意味します。形式と実際の文字列が合っていれば DateTime オブジェクトが返り、合わなければ false が返ります。

日付がずれる・意図しない値になる原因

日付処理は、書いたとおりに動かずに「9 時間ずれる」「false が返る」「変更したつもりが変わっていない」といったハマり方をしやすい分野です。代表的な原因を整理しておきましょう。

タイムゾーンが未設定で時刻がずれる

もっとも多いのが、タイムゾーンを設定していないために時刻が UTC で扱われ、日本時間と 9 時間ずれてしまうケースです。「日付をまたいで前日になってしまう」「深夜の処理で日付が 1 日ずれる」といった症状の多くはこれが原因です。前述の date_default_timezone_set("Asia/Tokyo") をスクリプトの先頭で呼ぶか、php.ini で date.timezone を設定しておきましょう。

strtotime が解釈できず false が返る

strtotime() は便利な反面、解釈できない文字列が来ると false を返します。たとえば「2026年6月4日」のような日本語表記や、存在しない「2026/13/40」のような日付は解釈できません。false をそのまま date() に渡すと 1970-01-01 付近の値になってしまうため、返り値が false でないかを必ずチェックしてから使うようにします。形式が決まっている入力では DateTime::createFromFormat() を使うほうが安全です。

strtotime-false.php
<?php
$ts = strtotime("2026/13/40");   // 不正な日付

if ($ts === false) {
    echo "日付として解釈できませんでした";
} else {
    echo date("Y-m-d", $ts);
}
// 出力: 日付として解釈できませんでした

DateTime を変更したつもりが共有されている

DateTimemodify()add() を呼ぶと、新しいオブジェクトを返すのではなく、自分自身の値を書き換えます(ミュータブル=可変)。そのため「元の日付を残したまま 1 日後を計算したい」つもりでも、元の変数まで一緒に変わってしまうという事故が起きます。

これを避けるには、値を書き換えない DateTimeImmutable クラスを使います。こちらは modify() などを呼ぶと元のオブジェクトはそのままに、変更後の新しいオブジェクトを返します。日付を使い回すコードでは DateTimeImmutable を選んでおくと、思わぬ書き換えを防げます。

immutable.php
<?php
// DateTime(可変): modify() で元の値まで変わる
$dt = new DateTime("2026-06-04");
$dt->modify("+1 day");
echo $dt->format("Y-m-d");   // 2026-06-05(元も変わってしまう)

echo "\n";

// DateTimeImmutable(不変): 戻り値を受け取る
$imm  = new DateTimeImmutable("2026-06-04");
$next = $imm->modify("+1 day");
echo $imm->format("Y-m-d")  . " / ";   // 2026-06-04(元はそのまま)
echo $next->format("Y-m-d");           // 2026-06-05(変更後)

DateTimeImmutablemodify() の戻り値を変数で受け取らないと、変更が反映されません。DateTime とは逆の感覚なので、両者の違いを意識して使い分けましょう。

まとめ

PHP の日付・時刻処理は、現在の日時を手軽に表示するなら date()、日付の計算や比較を行うなら DateTime クラス、と用途で使い分けるのが基本です。date()format() のフォーマット文字(Y m d H i s など)を覚えておけば、表示は自由自在になります。

計算では modify()DateInterval で加算・減算し、diff() で差分を求められます。そして実務で必ず効いてくるのが、Asia/Tokyo のタイムゾーン設定、strtotime() の戻り値チェック、そして値を書き換えない DateTimeImmutable の活用です。この 3 点を押さえておけば、日付がずれる・意図しない値になるといったトラブルの多くは防げます。

参考ページ