【PHP8.x】diffメソッドの使い方

diffメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

diffメソッドは、DateTimeImmutableオブジェクト間の差分をDateTimeオブジェクトとして取得するメソッドです。具体的には、このメソッドは2つのDateTimeImmutableオブジェクト(自身と引数として渡されたDateTimeImmutableオブジェクト)の日時情報の差を計算し、その結果をDateTimeオブジェクトとして返します。このDateTimeオブジェクトは、2つのDateTimeImmutableオブジェクト間の年、月、日、時、分、秒などの差分情報を保持します。

システム開発においては、日付や時間の差分を計算する場面は頻繁に発生します。例えば、イベントの期間計算、タスクの所要時間算出、経過時間の表示などに利用できます。diffメソッドを使用することで、これらの計算を簡単かつ正確に行うことができます。

引数には、比較対象となるDateTimeInterfaceオブジェクトを指定します。DateTimeInterfaceはDateTimeImmutableの親インターフェースであるため、DateTimeオブジェクトも渡すことが可能です。

戻り値はDateTimeオブジェクトとなり、このオブジェクトを通じて差分の情報を取得できます。例えば、$interval->yで年、$interval->mで月、$interval->dで日といったように、各要素にアクセスできます。

DateTimeオブジェクトが表すのはあくまで「差分」であり、特定の日時を表すものではない点に注意が必要です。差分オブジェクトから詳細な情報を取得するには、formatメソッドなどを使用する必要があります。

例として、あるタスクの開始日時と終了日時を表すDateTimeImmutableオブジェクトがある場合、diffメソッドを使ってそのタスクの所要時間をDateTimeオブジェクトとして取得し、さらにそのオブジェクトから必要な情報(例えば時間や分)を取り出して、所要時間を表示するといった処理が考えられます。

構文(syntax)

1DateTimeImmutable::diff( DateTimeInterface $targetObject, bool $absolute = false ): DateInterval

引数(parameters)

DateTimeInterface $targetObject, bool $absolute = false

  • DateTimeInterface $targetObject: 比較対象となる DateTimeInterface に準拠したオブジェクト
  • bool $absolute = false: 差を絶対値で取得するかどうか(true の場合、差は常に正の値になります)

戻り値(return)

DateTimeInterval

DateTimeImmutable::diff メソッドは、2つの DateTimeImmutable オブジェクトの差を計算し、その結果を DateTimeInterval オブジェクトとして返します。この DateTimeInterval オブジェクトには、日数、時間、分、秒などの時間間隔に関する情報が含まれています。

サンプルコード

PHP: DateTimeオブジェクトの==と===比較

1<?php
2
3/**
4 * この関数は、PHPにおける緩やかな等価性 (==) と厳密な等価性 (===) の比較演算子の違いを、
5 * DateTimeImmutableオブジェクトを例に示します。
6 *
7 * システムエンジニアを目指す初心者の方へ:
8 * == (緩やかな等価性): 値が同じであるかを比較します。型が異なっていても、PHPが型変換して値が一致すればtrueになります。
9 * === (厳密な等価性): 値と型が両方とも同じであるかを比較します。オブジェクトの場合は、
10 *                    同じメモリ上のインスタンスであるかどうかも確認します。
11 *                    つまり、厳密に同じオブジェクト参照である場合にのみtrueとなります。
12 */
13function demonstrateDateTimeComparisonOperators(): void
14{
15    // --------------------------------------------------------------------------
16    // シナリオ 1: 同じ日時を表す、別々のDateTimeImmutableオブジェクトの比較
17    // --------------------------------------------------------------------------
18    // 2つのDateTimeImmutableオブジェクトをそれぞれ独立して生成します。
19    // これらは同じ日時(値)を表しますが、メモリ上では別々のオブジェクトインスタンスです。
20    $date1 = new DateTimeImmutable('2023-01-15 10:30:00', new DateTimeZone('UTC'));
21    $date2 = new DateTimeImmutable('2023-01-15 10:30:00', new DateTimeZone('UTC'));
22
23    echo "--- シナリオ 1: \$date1 と \$date2 の比較 (同じ日時、異なるインスタンス) ---\n";
24    echo "Date 1: " . $date1->format('Y-m-d H:i:s P') . "\n";
25    echo "Date 2: " . $date2->format('Y-m-d H:i:s P') . "\n";
26
27    // 緩やかな等価性 (==) で比較:
28    // DateTimeImmutableオブジェクトの場合、== は両方のオブジェクトが同じ時点を指す場合にtrueを返します。
29    echo "\$date1 == \$date2 (緩やかな等価性): " . (($date1 == $date2) ? 'true' : 'false') . "\n";
30    // 期待される結果: true (両者とも '2023-01-15 10:30:00 UTC' を表すため)
31
32    // 厳密な等価性 (===) で比較:
33    // === は、両方の変数が同じ型の、全く同じオブジェクトインスタンスを参照している場合にのみtrueを返します。
34    // ここでは、それぞれ new DateTimeImmutable で作成された別々のインスタンスなので false になります。
35    echo "\$date1 === \$date2 (厳密な等価性): " . (($date1 === $date2) ? 'true' : 'false') . "\n";
36    // 期待される結果: false (別々のオブジェクトインスタンスであるため)
37
38    // 参考: diffメソッドで時間差を確認。時間が同じなら0時間の差になります。
39    $interval12 = $date1->diff($date2);
40    echo "DateTimeImmutable::diff(\$date1, \$date2) の差: "
41        . $interval12->format('%y年 %mヶ月 %d日 %h時間 %i分 %s秒') . "\n";
42    // 期待される結果: 全て0 (日時が同じであるため)
43    echo "\n";
44
45
46    // --------------------------------------------------------------------------
47    // シナリオ 2: 元のオブジェクトへの直接参照の比較
48    // --------------------------------------------------------------------------
49    // $date3 は $date1 と全く同じオブジェクトインスタンスを指します。
50    $date3 = $date1;
51
52    echo "--- シナリオ 2: \$date1 と \$date3 の比較 (同じ日時、同じインスタンス) ---\n";
53    echo "Date 1: " . $date1->format('Y-m-d H:i:s P') . "\n";
54    echo "Date 3: " . $date3->format('Y-m-d H:i:s P') . "\n";
55
56    // 緩やかな等価性 (==) で比較:
57    echo "\$date1 == \$date3 (緩やかな等価性): " . (($date1 == $date3) ? 'true' : 'false') . "\n";
58    // 期待される結果: true (同じオブジェクトなので、当然値も同じ)
59
60    // 厳密な等価性 (===) で比較:
61    // $date3 は $date1 への直接参照なので、これらは全く同じオブジェクトインスタンスです。
62    echo "\$date1 === \$date3 (厳密な等価性): " . (($date1 === $date3) ? 'true' : 'false') . "\n";
63    // 期待される結果: true (全く同じオブジェクトインスタンスであるため)
64    echo "\n";
65
66
67    // --------------------------------------------------------------------------
68    // シナリオ 3: 元のオブジェクトのクローン (複製) の比較
69    // --------------------------------------------------------------------------
70    // $date4 は $date1 のクローンです。これは $date1 と同じ値を持つ新しいオブジェクトインスタンスです。
71    $date4 = clone $date1;
72
73    echo "--- シナリオ 3: \$date1 と \$date4 の比較 (同じ日時、クローンによる異なるインスタンス) ---\n";
74    echo "Date 1: " . $date1->format('Y-m-d H:i:s P') . "\n";
75    echo "Date 4: " . $date4->format('Y-m-d H:i:s P') . "\n";
76
77    // 緩やかな等価性 (==) で比較:
78    echo "\$date1 == \$date4 (緩やかな等価性): " . (($date1 == $date4) ? 'true' : 'false') . "\n";
79    // 期待される結果: true (クローンなので、値は同じ)
80
81    // 厳密な等価性 (===) で比較:
82    // 'clone' は新しいオブジェクトインスタンスを作成するため、$date1 と $date4 は別々のインスタンスです。
83    echo "\$date1 === \$date4 (厳密な等価性): " . (($date1 === $date4) ? 'true' : 'false') . "\n";
84    // 期待される結果: false (別々のオブジェクトインスタンスであるため)
85
86    // 参考: diffメソッドで時間差を確認。時間が同じなら0時間の差になります。
87    $interval14 = $date1->diff($date4);
88    echo "DateTimeImmutable::diff(\$date1, \$date4) の差: "
89        . $interval14->format('%y年 %mヶ月 %d日 %h時間 %i分 %s秒') . "\n";
90    // 期待される結果: 全て0 (日時が同じであるため)
91    echo "\n";
92}
93
94// 関数を実行して比較の結果を出力します。
95demonstrateDateTimeComparisonOperators();

PHPにおける== (緩やかな等価性) と === (厳密な等価性) は、値の比較において重要な違いがあります。==は、左右の値が同じであるかを比較し、必要に応じてPHPが型変換を行ってから判断します。一方、===は値が同じであることに加え、型も全く同じであるかを厳密に比較します。特にDateTimeImmutableのようなオブジェクトの場合、==はオブジェクトが示す日付と時刻の値が同じであればtrueを返しますが、===はメモリ上で全く同じオブジェクトインスタンスを参照している場合にのみtrueとなります。

サンプルコードでは、同じ日時を持つ別々のDateTimeImmutableオブジェクトを==で比較するとtrueとなり、===ではfalseとなる様子を示しています。これは、値は同じでも参照しているインスタンスが異なるためです。しかし、直接参照をコピーしたオブジェクトや、クローンしたオブジェクトでは、===の結果が異なることを確認できます。

この文脈で利用されるDateTimeImmutable::diffメソッドは、2つのDateTimeInterfaceオブジェクト間の時間差を計算するためのものです。引数$targetObjectには比較対象となる日時オブジェクトを指定し、オプションの$absolute引数(デフォルトはfalse)で差の絶対値を返すかを指定します。このメソッドは計算された時間差をDateTimeIntervalオブジェクトとして返します。サンプルコードでは、比較している日時が同じである場合、diffメソッドが「0秒」といった差を返すことを補足的に示し、日時が一致していることの確認にも利用できることを解説しています。

PHPのオブジェクト比較において、==(緩やかな等価性)と===(厳密な等価性)の挙動は特に注意が必要です。DateTimeImmutableオブジェクトの場合、==は「日時という値」が同じであればtrueを返します。しかし、===は「値」だけでなく、メモリ上の全く同じオブジェクトインスタンスであるかどうかも比較するため、たとえ同じ日時を表す別々のnewで生成されたオブジェクトやcloneで複製されたオブジェクトではfalseとなります。完全に同じオブジェクト参照の場合のみ===はtrueです。一方、diffメソッドは二つのDateTimeImmutableオブジェクト間の期間をDateTimeIntervalとして返しますので、時間差がゼロであることを確認することで、値としての等価性を明確に判定できます。比較の目的に応じて適切な演算子やメソッドを選ぶことが、コードを正確に理解し、意図しない挙動を防ぐ上で重要です。

PHPで2つの日付の差を計算する

1<?php
2
3/**
4 * 2つの日付間の差を計算し、表示するサンプルコードです。
5 * DateTimeImmutable::diff メソッドの使用方法を示します。
6 * DateTimeImmutable オブジェクトは、一度作成されると状態が変更されない(不変である)ため、
7 * 予期せぬ変更を防ぎ、安全に日付操作を行うことができます。
8 */
9function calculateDateDifference(): void
10{
11    // 比較する最初のDateTimeImmutableオブジェクトを作成します。
12    // 日付と時刻を指定してオブジェクトを初期化します。
13    $startDate = new DateTimeImmutable('2023-01-15 10:30:00');
14    echo "開始日時: " . $startDate->format('Y-m-d H:i:s') . "\n";
15
16    // 比較する2番目のDateTimeImmutableオブジェクトを作成します。
17    $endDate = new DateTimeImmutable('2024-03-20 14:45:30');
18    echo "終了日時: " . $endDate->format('Y-m-d H:i:s') . "\n\n";
19
20    // diffメソッドを使用して、2つのDateTimeImmutableオブジェクト間の差を計算します。
21    // このメソッドはDateTimeIntervalオブジェクトを返します。
22    // 第2引数 $absolute はデフォルトで false なので、期間の符号は日付の順序によって決まります。
23    $interval = $startDate->diff($endDate);
24
25    echo "=== 計算された日付の差 (各要素) ===\n";
26    // DateTimeIntervalオブジェクトのプロパティから、各要素(年、月、日、時、分、秒など)を取得できます。
27    echo "年: " . $interval->y . "年\n";
28    echo "月: " . $interval->m . "ヶ月\n";
29    echo "日: " . $interval->d . "日\n";
30    echo "時: " . $interval->h . "時間\n";
31    echo "分: " . $interval->i . "分\n";
32    echo "秒: " . $interval->s . "秒\n";
33    // 総日数を取得します。これは期間の絶対的な日数を表します。
34    echo "総日数: " . $interval->days . "日\n";
35    // invert プロパティは、期間が負(開始日が終了日より後)の場合に 1、正の場合に 0 を返します。
36    echo "期間の方向 (0:正, 1:負): " . $interval->invert . "\n";
37
38    echo "\n=== フォーマットされた日付の差 ===\n";
39    // formatメソッドを使うと、指定した形式で日付の差を文字列として取得できます。
40    // %y: 年, %m: 月, %d: 日, %h: 時, %i: 分, %s: 秒, %a: 総日数
41    echo "詳細な差: " . $interval->format('%y年%mヶ月%d日 %h時間%i分%s秒') . "\n";
42    echo "総日数の差: " . $interval->format('%a日') . "\n";
43}
44
45// 上記で定義した日付差計算関数を実行します。
46calculateDateDifference();
47

PHP 8のDateTimeImmutable::diffメソッドは、二つの日付と時刻の間の差を計算するために利用されます。DateTimeImmutableクラスは、一度作成されると内容が変更されない「不変」のオブジェクトであるため、予期せぬ変更を防ぎ、安全に日付操作を行うのに適しています。

このメソッドは、呼び出し元のDateTimeImmutableオブジェクトから、引数として渡される$targetObjectDateTimeInterfaceを実装した別の datetime オブジェクト)までの期間を計算します。第二引数$absoluteは期間の絶対値を取るかを指定し、デフォルトのfalseでは日付の順序によって期間の正負が決まります。

diffメソッドは、計算された期間の詳細情報を持つDateTimeIntervalオブジェクトを返します。このDateTimeIntervalオブジェクトには、年(y)、月(m)、日(d)、時(h)、分(i)、秒(s)といった各要素ごとの差や、期間の総日数(days)、期間の方向を示すinvertプロパティなどが含まれています。サンプルコードでは、これらのプロパティに直接アクセスして各要素を表示するほか、DateTimeInterval::formatメソッドを使用して「%y年%mヶ月%d日 %h時間%i分%s秒」や「%a日」のように、指定された形式で期間を整形された文字列として出力する方法を示しています。これにより、日付間の期間を多様な形式で取得し、活用することができます。

DateTimeImmutable::diffメソッドは、日付オブジェクトが不変であるため、元のオブジェクトを不用意に変更する心配なく安全に日付差を計算できます。このメソッドは直接文字列ではなくDateTimeIntervalオブジェクトを返すため、年や月などの個別の要素は$interval->yなどのプロパティで、総日数は$interval->daysプロパティまたは$interval->format('%a')で取得します。期間の前後関係は$interval->invertプロパティで確認できます。また、diffメソッドの第2引数$absolutetrueにすると、常に期間の絶対値が返されるため、符号を気にせず期間の長さを把握したい場合に活用すると良いでしょう。

【PHP8.x】diffメソッドの使い方 | いっしー@Webエンジニア