日付・時間

PHP DateTimeImmutableの基本と活用方法について解説

PHPのDateTimeImmutableクラスは、一度生成すると状態が変化せず、その後の操作で元の日時データに影響が及ばない仕組みです。

変更が必要な場合は必ず新しいオブジェクトが返され、意図しない副作用を防止できます。

この記事では、基本的な使い方やメリット、具体的な活用例について解説します。

インスタンス生成と初期設定

現在日時の生成

new DateTimeImmutable() の利用方法

PHPで現在日時のインスタンスを生成する場合、new DateTimeImmutable() を利用します。

引数を省略すると、サーバの現在日時が自動的に設定されます。

以下のサンプルコードは、現在日時のオブジェクトを生成し、フォーマットで表示する例です。

<?php
// 現在日時のインスタンスを生成
$currentDate = new DateTimeImmutable();
// インスタンスを指定フォーマットで表示
echo $currentDate->format('Y-m-d H:i:s');
?>
2023-10-01 15:45:30

現在日時取得のポイント

new DateTimeImmutable() を利用すると、生成時点の日時が確定しており、再利用しても変更されません。

・タイムゾーンが明示されていない場合、php.iniの設定またはdate_default_timezone_set によるデフォルトタイムゾーンが使用されます。

・不変性により、オブジェクトの状態が更新される際は新たなインスタンスが返され、元のインスタンスは変更されない点に注意してください。

文字列から日時の作成

createFromFormat メソッドの使い方

特定のフォーマットの文字列から日時のオブジェクトを生成する場合、DateTimeImmutable::createFromFormat を利用します。

フォーマットと文字列が一致している場合に正しく日時オブジェクトが作成されます。

<?php
// 指定フォーマットの文字列から日時を生成
$dateString = '2023-10-01 12:34:56';
$date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $dateString);
if ($date === false) {
    // 生成に失敗した場合の処理
    echo "日時の作成に失敗しました";
} else {
    echo $date->format('Y-m-d H:i:s');
}
?>
2023-10-01 12:34:56

フォーマット指定とエラーの取り扱い

・文字列とフォーマットの不一致が生じると、createFromFormatfalseを返します。

・エラー情報を取得する場合は、DateTimeImmutable::getLastErrors() を利用することで、どの部分でエラーが発生したか確認できます。

・入力値が厳密な形式であることを確認し、エラーハンドリングを適切に行うことが重要です。

日付・時刻の演算

日付加算と減算

modify メソッドによる演算

modifyメソッドを利用することで、日時に対して文字列で指定した加算や減算を行うことができます。

新たなオブジェクトが返されるため、元の日時は変更されません。

<?php
// 基準となる日時を生成
$date = new DateTimeImmutable('2023-10-01');
// 1日加算する例
$newDate = $date->modify('+1 day');
// 2日前に減算する例
$oldDate = $date->modify('-2 days');
echo $newDate->format('Y-m-d') . "\n";
echo $oldDate->format('Y-m-d');
?>
2023-10-02
2023-09-29

add と sub の使い分け

addメソッドと subメソッドは、それぞれ DateIntervalオブジェクトを受け取り、加算および減算を行います。

計算結果は新しい日時オブジェクトとして返されます。

<?php
// 基準となる日時を生成
$date = new DateTimeImmutable('2023-10-01');
// 3日間のインターバルを作成
$interval = new DateInterval('P3D');
// 日付を3日加算する例
$newDate = $date->add($interval);
// 日付を3日減算する例
$oldDate = $date->sub($interval);
echo $newDate->format('Y-m-d') . "\n";
echo $oldDate->format('Y-m-d');
?>
2023-10-04
2023-09-28

個別フィールドの更新

更新操作で新オブジェクトが返る仕組み

DateTimeImmutable では、日時に対するいかなる更新操作も新規のインスタンスを返します。

そのため、元の日時オブジェクトは変更されず、複数のバージョンを保持できます。

<?php
// 初期日時を生成
$originalDate = new DateTimeImmutable('2023-10-01 10:00:00');
// 2時間加算して新しいインスタンスを作成
$updatedDate = $originalDate->modify('+2 hours');
echo $originalDate->format('H:i:s') . "\n"; // 元の日時
echo $updatedDate->format('H:i:s');         // 更新後の日時
?>
10:00:00
12:00:00

時刻要素の部分変更方法

時刻の一部(例えば、時間だけ)を更新したい場合は、setTimeメソッドを利用するとシンプルです。

これにより、分や秒もまとめて指定することができます。

<?php
// 初期日時を生成
$originalDate = new DateTimeImmutable('2023-10-01 10:30:00');
// 時刻だけを変更(15時30分に設定)
$updatedDate = $originalDate->setTime(15, 30, 0);
echo $originalDate->format('H:i:s') . "\n"; // 元のタイム
echo $updatedDate->format('H:i:s');         // 更新後のタイム
?>
10:30:00
15:30:00

タイムゾーンの操作

インスタンス生成時のタイムゾーン指定

明示的なタイムゾーン設定方法

新たな日時オブジェクトを生成する際には、DateTimeZoneオブジェクトをコンストラクタに渡すことで、タイムゾーンを明示的に指定できます。

<?php
// タイムゾーンを指定して生成
$timezone = new DateTimeZone('Asia/Tokyo');
$date = new DateTimeImmutable('now', $timezone);
echo $date->format('Y-m-d H:i:s') . ' Asia/Tokyo';
?>
2023-10-01 15:45:30 Asia/Tokyo

デフォルトタイムゾーンとの関係

・タイムゾーンを指定せずにインスタンスを生成した場合、PHPのデフォルトタイムゾーンが使用されます。

・デフォルトタイムゾーンは、date_default_timezone_set('Asia/Tokyo') などで変更可能です。

・明示的なタイムゾーン設定は、異なる地域の時間を正確に扱う際に有用です。

タイムゾーン変更の操作

setTimezone メソッドの利用時の注意点

setTimezoneメソッドを利用すると、同じ瞬間を指す日時オブジェクトのタイムゾーン表示が変更されます。

内部的なUNIXタイムスタンプは保持されるため、実際の時刻は変わらず、表示上の値が変化する点に注意が必要です。

<?php
// Asia/Tokyo のタイムゾーンで日時を生成
$timezoneTokyo = new DateTimeZone('Asia/Tokyo');
$date = new DateTimeImmutable('2023-10-01 12:00:00', $timezoneTokyo);
// UTCにタイムゾーンを変更
$timezoneUtc = new DateTimeZone('UTC');
$utcDate = $date->setTimezone($timezoneUtc);
echo $date->format('Y-m-d H:i:s T') . "\n";   // Asia/Tokyo 表示
echo $utcDate->format('Y-m-d H:i:s T');         // UTC 表示
?>
2023-10-01 12:00:00 JST
2023-10-01 03:00:00 UTC

DateTimeとの違い

不変性の特性

オブジェクト更新時の挙動の違い

DateTimeImmutable は更新操作を行うと常に新しいインスタンスを返します。

これに対して、DateTime は内部状態を変更するため、後続の処理に影響を与える可能性があります。

以下のサンプルコードでは、古いインスタンスと更新後のインスタンスで異なる時刻が表示される点を確認できます。

<?php
// DateTimeImmutable により初期日時を生成
$date = new DateTimeImmutable('2023-10-01 10:00:00');
// 1時間加算して新しいインスタンスを生成
$newDate = $date->modify('+1 hour');
echo $date->format('H:i:s') . "\n";    // 元の日時
echo $newDate->format('H:i:s');        // 更新後の日時
?>
10:00:00
11:00:00

利用シーンの比較

状態管理における選択基準

・状態の更新や変更履歴を管理する場合、オブジェクトが不変であることにより予期せぬ副作用を防止できます。

・一方、オブジェクトの更新が頻繁に行われる処理では、同じインスタンスを再利用するDateTime が便利な場合もあります。

・選択の際は、システム全体の設計や求められる安全性、可読性を考慮して適切なクラスを利用してください。

エラー処理と注意事項

無効な日時入力時の対処

例外発生条件の確認

DateTimeImmutable::createFromFormat で不正な日時文字列を与えた場合、falseが返されるため、エラー処理を適切に行う必要があります。

エラー情報の取得には、DateTimeImmutable::getLastErrors() を利用することで、どこでエラーが発生したかを確認できます。

<?php
// 無効な日時文字列を入力する例
$dateString = 'invalid-date';
$date = DateTimeImmutable::createFromFormat('Y-m-d', $dateString);
if ($date === false) {
    // エラー情報を取得して表示
    $errors = DateTimeImmutable::getLastErrors();
    echo "エラーが発生しました:\n";
    print_r($errors);
} else {
    echo $date->format('Y-m-d');
}
?>
エラーが発生しました:
Array
(
    [warning_count] => 1
    [warnings] => Array
        (
            [10] => The parsed date was invalid
        )
    [error_count] => 0
    [errors] => Array
        (
        )
)

メソッド実行時の留意点

更新操作に伴う挙動の確認

複数回の更新操作を連続して行う場合、各操作は新しいインスタンスを返すため、その都度返されたオブジェクトを受け取る必要があります。

元のオブジェクトを使い回すと、意図しない結果になる可能性があるため注意が必要です。

<?php
// 基本となる日時オブジェクトを生成
$date = new DateTimeImmutable('2023-10-01 08:00:00');
// 2時間加算したインスタンスを生成し、その後さらに30分加算する
$dateModified = $date->modify('+2 hours');
$dateFurther = $dateModified->modify('+30 minutes');
echo $date->format('H:i:s') . "\n";         // 初期日時
echo $dateModified->format('H:i:s') . "\n";   // 2時間加算後
echo $dateFurther->format('H:i:s');           // さらに30分加算後
?>
08:00:00
10:00:00
10:30:00

まとめ

この記事ではPHPのDateTimeImmutableを用いて、現在日時の生成、文字列からの日時作成、日付・時刻の演算、タイムゾーン操作、DateTimeとの違いやエラー処理について詳しくご紹介しました。

各操作の基本的な使い方と、オブジェクトが不変であることのメリット・注意点を短くまとめています。

今後はぜひ、実際にコードを試して、DateTimeImmutableの利便性を体感してみてください。

関連記事

Back to top button
目次へ