CakeFest 2024: The Official CakePHP Conference

DateTimeImmutable::createFromFormat

date_create_immutable_from_format

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

DateTimeImmutable::createFromFormat -- date_create_immutable_from_format時刻の文字列を指定されたフォーマットに従ってパースする

説明

オブジェクト指向型

public static DateTimeImmutable::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null): DateTimeImmutable|false

手続き型

新しい DateTimeImmutable オブジェクトを返します。 このオブジェクトは、datetime で指定した文字列を format で指定した書式に沿って解釈した時刻を表します。

パラメータ

format

書式を文字列で渡します。以下の書式オプションを参照ください。 大半は、date() で使える文字と同じです。

全てのフィールドは現在の日付/時刻で初期化されます。 ほとんどの場合、これらの値を "ゼロ" (Unix タイムのエポック 1970-01-01 00:00:00 UTC) でリセットしたいはずです。 これは、format の最初の文字に ! を入れるか、 最後の文字に | を入れることで実現できます。 詳細な情報は、以下で示すそれぞれの文字に関するドキュメントを参照ください。

フォーマットの解釈は左から右に行われます。 これは、フォーマット文字が現れる順番が結果に影響する場合があるということです。 たとえば z(1年における何番目の日か) の場合、 Yy を使って年が既にパースされた後に使わなければなりません。

数値の解釈に使われる文字については、広範な値が許されています。 これには、論理的に許される範囲以上のものも含みます。 たとえば、d (ある月における何番目の日か) の場合、 00 から 99 までの値が許されています。これに対する唯一の制約は、桁数のみです。 範囲外の値が指定された場合、 日付/時刻のパーサーのオーバーフローの仕組みが使われます。 オーバーフローのふるまいについては、 後にいくつかのサンプルを示します。

データは、フォーマット文字に従って貪欲にパースされます。 つまり、そのフォーマットが許している最大の長さまで読みこまれます。 これによって、次のフォーマット文字に十分な文字数が datetime にもう残っていないことがありえます。 このことが引き起こす問題については、このページのサンプルでも触れます。

format パラメータに渡せる文字
format 文字 説明 取りうる値の例
--- ---
d および j 2桁の日付。先頭のゼロを含むものと含まないもの 01 から 31 あるいは 1 から 31 (その月の日数分以上の2桁の数値も指定可能ですが、 その月はオーバーフローします。 たとえば January において 33 を指定した場合、 February 2nd という意味になります)
D および l 曜日を表す文字列 Mon から Sun あるいは Sunday から Saturday。 指定された曜日が、パースされた(またはデフォルトの)日付と異なっていた場合、 指定された曜日の 次の 日にオーバーフローします。詳細は後に示すサンプルを参照ください。
S 日付の後につける英語の接尾辞。二文字。処理中には無視されます。 stndrd あるいは th
z 年始からの通算日数 (最初は 0)。 Y または y の後に続けて置かなければいけません。 0 から 365 (1年の日数分以上の3桁の数値も指定可能ですが、 その年はオーバーフローします。 たとえば 2022年において 366 を指定した場合は、 January 2nd, 2023 という意味になります)
--- ---
F および M 月を表す文字列。January あるいは Sept など January から December あるいは Jan から Dec
m および n 月を表す数値。先頭のゼロを含むものと含まないもの 01 から 12 あるいは 1 から 12 (12 以上の2桁の数値も指定可能ですが、 その年についてはオーバーフローします。 たとえば 13 の場合は、 翌年の1月という意味になります)
--- ---
X および x 年の数値表現。19桁まで指定可能。オプションで +- を先頭に指定可能です。 例: 0055, 787, 1999, -2003, +10191
Y 4 桁以下の数値で表した年 例: 0055, 787, 1999, 2003
y 2 桁の数値で表した年 (1970年から2069年の間だとみなされます) 例: 99 あるいは 03 (それぞれ、 1999 および 2003 と見なされます)
時刻 --- ---
a および A 午前および午後 am あるいは pm
g および h 12 時間制での時間。先頭のゼロを含むものと含まないもの 1 から 12 あるいは 01 から 12 (12 以上の2桁の数値も指定可能ですが、 日の指定がオーバーフローします。 たとえば 14 の場合は、 次の午前/午後の 02 時という意味になります)
G および H 24 時間制での時間。先頭のゼロを含むものと含まないもの 0 から 23、あるいは 00 から 23 (24 より大きな、2桁の値も指定可能ですが、 この場合、日の指定がオーバーフローします。 たとえば、26 は翌日の 02:00 という意味になります)
i 分。先頭のゼロを含む 00 から 59 (59 以上の2桁の数値も指定可能ですが、 次の1時間にオーバーフローします。 たとえば 66 の場合は、 次の1時間の :06 という意味になります)
s 秒。先頭のゼロを含む 00 から 59 (59 以上の2桁の数値も指定可能ですが、 次の分にオーバーフローします。 たとえば 90 の場合は、 次の分の :30 という意味になります)
v ミリ秒 (最大 3桁) 例: 12 (0.12 秒という意味), 345 (0.345 秒という意味)
u マイクロ秒 (最大 6 桁) 例: 45 (0.45 秒という意味), 654321 (0.654321 秒という意味)
タイムゾーン --- ---
eOP および T タイムゾーン識別子、UTC からの時差 (時間単位)、 UTC からの時差 (コロン区切りでの時間と分)、そしてタイムゾーンの短縮形 例: UTCGMTAtlantic/Azores+0200+02:00ESTMDT
完全な日付/時刻 --- ---
U Unix エポック (January 1 1970 00:00:00 GMT) からの経過秒数 例: 1292177455
空白および区切り --- ---
(空白) ゼロ文字以上のスペース、タブ、NBSP(U+A0)、NNBSP(U+202F) 例: "\t", " "
# 次の区切り文字のいずれか: ;, :, /, ., ,, -, (, ) 例: /
;, :, /, ., ,, -, (, ) 指定した文字 例: -
? ランダムなバイト 例: ^ (UTF-8 文字の場合は複数の ? が必要になるでしょう。この場合、おそらく * を使うと要望が満たせるはずです)
* 次の区切り文字あるいは数字までのランダムなバイト列 例: Y-*-d の中の * は、文字列 2009-aWord-08 の中の aWord にマッチします
! すべてのフィールド (年、月、日、時、分、秒、マイクロ秒およびタイムゾーン情報) を ゼロ相当の値 (時、分、秒、マイクロ秒については 0。 月、日については 1。 年については 1970。 タイムゾーンについては UTC) にリセットします。 ! がなければ、すべてのフィールドは現在の日時に設定されます。
| まだパースされていないすべてのフィールド (年、月、日、時、分、秒、マイクロ秒およびタイムゾーン情報) を ゼロ相当の値にリセットします。 Y-m-d| は、文字列をパースした結果から年月日を設定し 時分秒には 0 を設定します。
+ この文字があると、文字列のそれ以降のデータではエラーが発生せず、 かわりに警告を発生させる それ以降のデータが存在したかどうかを調べるには DateTime::getLastErrors() を使います。

書式文字列の中に解釈不能な文字が含まれていると処理は失敗し、 戻り値にはエラーメッセージが付加されます。エラーメッセージを調べるには DateTime::getLastErrors() を使います。

format にリテラル文字を含めるには、 バックスラッシュ (\) でエスケープする必要があります。

format に文字 ! が含まれない場合は、作成した時刻値のうち format で指定されていない部分を 現在のシステム時刻で初期化します。

format に文字 ! が含まれる場合は、作成した時刻値のうち format で指定されていない部分と ! の左側の部分を Unix エポックの対応する箇所の値で初期化します。

Unix エポックは 1970-01-01 00:00:00 です。

datetime

時刻を表す文字列。

timezone

指定したいタイムゾーンを表す DateTimeZone オブジェクト。

timezone を省略されるか、または null の場合、 かつ datetime にタイムゾーンが含まれない場合は、 現在のタイムゾーンを使います。

注意:

datetime パラメータが UNIX タイムスタンプ (例: 946684800) だったり、タイムゾーンを含んでいたり (例: 2010-01-28T15:00:00+02:00) する場合は、 timezone パラメータや現在のタイムゾーンは無視します。

戻り値

新しい DateTimeImmutable のインスタンスを返します。 失敗した場合に false を返します.

エラー / 例外

datetime に NULLバイトが含まれている場合は、 ValueError がスローされます。

変更履歴

バージョン 説明
8.2.9 (空白) 文字は、 新たに NBSP(U+A0) と NNBSP(U+202F) をサポートするようになりました。
8.2.0 format に指定できる文字に、 Xx が追加されました。
8.0.21, 8.1.8, 8.2.0 datetime に NULLバイトが含まれている場合は、 ValueError がスローされるようになりました。 これより前のバージョンでは、こうした値は静かに無視されていました。
7.3.0 format に指定できる文字に、 v が追加されました。

例1 DateTimeImmutable::createFromFormat() の例

オブジェクト指向型

<?php
$date
= DateTimeImmutable::createFromFormat('j-M-Y', '15-Feb-2009');
echo
$date->format('Y-m-d');
?>

例2 定義済みのフォーマットの定数を DateTimeImmutable::createFromFormat() で使う

オブジェクト指向型

<?php
$date
= DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, '2004-02-12T15:19:21+00:00');
$date = DateTimeImmutable::createFromFormat(DateTimeInterface::RFC3339_EXTENDED, '2013-10-14T09:00:00.000+02:00');
?>

この例で使われている 定義済みの定数 は、DateTimeImmutableフォーマット 文字からなる文字列です。 ほとんどの場合、それらのフォーマット文字は 上の パラメータ で定義されている 日付/時刻 の要素とマッチしますが、 カバーしている範囲は狭いです。

例3 DateTimeImmutable::createFromFormat() の複雑な例

<?php
echo 'Current time: ' . date('Y-m-d H:i:s') . "\n";

$format = 'Y-m-d';
$date = DateTimeImmutable::createFromFormat($format, '2009-02-15');
echo
"Format: $format; " . $date->format('Y-m-d H:i:s') . "\n";

$format = 'Y-m-d H:i:s';
$date = DateTimeImmutable::createFromFormat($format, '2009-02-15 15:16:17');
echo
"Format: $format; " . $date->format('Y-m-d H:i:s') . "\n";

$format = 'Y-m-!d H:i:s';
$date = DateTimeImmutable::createFromFormat($format, '2009-02-15 15:16:17');
echo
"Format: $format; " . $date->format('Y-m-d H:i:s') . "\n";

$format = '!d';
$date = DateTimeImmutable::createFromFormat($format, '15');
echo
"Format: $format; " . $date->format('Y-m-d H:i:s') . "\n";

$format = 'i';
$date = DateTimeImmutable::createFromFormat($format, '15');
echo
"Format: $format; " . $date->format('Y-m-d H:i:s') . "\n";
?>

上の例の出力は、 たとえば以下のようになります。

Current time: 2022-06-02 15:50:46
Format: Y-m-d; 2009-02-15 15:50:46
Format: Y-m-d H:i:s; 2009-02-15 15:16:17
Format: Y-m-!d H:i:s; 1970-01-15 15:16:17
Format: !d; 1970-01-15 00:00:00
Format: i; 2022-06-02 00:15:00

例4 リテラル文字を含む書式文字列

<?php
echo DateTimeImmutable::createFromFormat('H\h i\m s\s','23h 15m 03s')->format('H:i:s');
?>

上の例の出力は、 たとえば以下のようになります。

23:15:03

例5 オーバーフローした際のふるまい

<?php
echo DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2021-17-35 16:60:97')->format(DateTimeImmutable::RFC2822);
?>

上の例の出力は、 たとえば以下のようになります。

Sat, 04 Jun 2022 17:01:37 +0000

上の結果は奇妙に見えますが、正しい動作です。 なぜなら、以下のようなオーバーフローが発生しているからです:

  1. 97 秒は 1 分オーバーフローしており、37 秒が残ります。
  2. 61 分は 1 時間オーバーフローしており、1 分が残ります。
  3. 35 日は、1 ヶ月分オーバーフローしており、4 日が残ります。 どれだけの日が残るかは月に依存します。 なぜなら、すべての月が同じ日数を持つとは限らないからです。
  4. 18 ヶ月は、1 年分オーバーフローしており、6 ヶ月が残ります。

例6 曜日がオーバーフローした場合のふるまい

<?php
$d
= DateTime::createFromFormat(DateTimeInterface::RFC1123, 'Mon, 3 Aug 2020 25:00:00 +0000');
echo
$d->format(DateTime::RFC1123), "\n";
?>

上の例の出力は、 たとえば以下のようになります。

Mon, 10 Aug 2020 01:00:00 +0000

上の結果は奇妙に見えますが、正しい動作です。 なぜなら、以下のようなオーバーフローが発生しているからです:

  1. 3 Aug 2020 25:00:00 はオーバーフローしており、(Tue) 4 Aug 2020 01:00 となります。
  2. Mon が適用されます。 これは、日付が Mon, 10 Aug 2020 01:00:00 まで進むからです。 Mon のような相対的なキーワード指定については、 相対的な書式 で説明されています。

日付のオーバーフローを検出するために、 DateTimeImmutable::getLastErrors() が使えます。 このメソッドの結果には、オーバーフローが発生した場合に警告が含まれます。

例7 オーバーフローした日付を検出する

<?php
$d
= DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2021-17-35 16:60:97');
echo
$d->format(DateTimeImmutable::RFC2822), "\n\n";

var_dump(DateTimeImmutable::GetLastErrors());
?>

上の例の出力は、 たとえば以下のようになります。

Sat, 04 Jun 2022 17:01:37 +0000

array(4) {
  'warning_count' =>
  int(2)
  'warnings' =>
  array(1) {
    [19] =>
    string(27) "The parsed date was invalid"
  }
  'error_count' =>
  int(0)
  'errors' =>
  array(0) {
  }
}

例8 貪欲なパースの振る舞い

<?php
print_r
(date_parse_from_format('Gis', '60101'));
?>

上の例の出力は、 たとえば以下のようになります。

Array
(
    [year] =>
    [month] =>
    [day] =>
    [hour] => 60
    [minute] => 10
    [second] => 0
    [fraction] => 0
    [warning_count] => 1
    [warnings] => Array
        (
            [5] => The parsed time was invalid
        )

    [error_count] => 1
    [errors] => Array
        (
            [4] => A two digit second could not be found
        )

    [is_localtime] =>
)

フォーマット文字 G は、 24時間制での時間をパースします。 先頭のゼロを含んでいても、含まなくてもパースを行います。 このフォーマットは、1桁か2桁の数値が必要ですが、 2桁の数値が存在するので、ここでは貪欲に 60 を読み込みます。

その後に続く is フォーマット文字は、両方2桁の数値が必要です。 つまり、10 が (フォーマット文字 i の) 分として渡されるので、 (フォーマット文字 s の) 秒としてパースする十分な桁数が残っていません。

配列の errors キーの内容が、 この問題を説明しています。

さらに、24時間制の時は、 0-24 の範囲であるため、 60 は範囲外の値です。 よって、warnings キーに、 指定された時間が正しくない旨の警告が含まれています。

参考

add a note

User Contributed Notes 3 notes

up
1
Tessa at AuRiseCreative dot com
1 month ago
Since the description and examples don't exactly match for the timezone row, I want to clarify exactly which format each character outputs.

`e` outputs the timezone identifier, e.g. `America/New_York` or `Asia/Gaza`

`O` outputs the difference to UTC in hours, e.g. `-0500` or `+0200`

`P` outputs difference to UTC with a colon between hours and minutes, e.g. `-05:00` or `+02:00`

`T` outputs the timezone abbreviation, e.g. `EST` or `EET`
up
0
peter dot labos at gmail dot com
2 months ago
If you are not happy with wide range of conversions and repairs this method is making for you, or just want to check that date is really same as input:

```
$datetime = \DateTimeImmutable::createFromFormat('Y-m-d G:i:s', $userDateTimeInput);

if ($datetime && $datetime->format('Y-m-d G:i:s') === $userDateTimeInput) {
// $datetime is not false and we have a correct date in correct format from user
}
```
up
0
Andy Walker
1 year ago
To clarify, g/G are 12/24 hour time without a leading 0, and h/H are 12/24 hour time with a leading zero, as described here:

https://www.php.net/manual/en/datetime.format.php
To Top