PHP Conference Japan 2024

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(字串 $format, 字串 $datetime, ?DateTimeZone $timezone = null): DateTimeImmutable|false

程序式風格

傳回一個新的 DateTimeImmutable 物件,表示由 datetime 字串指定的日期和時間,該字串的格式為指定的 format

參數

format

傳入的 字串 應使用的格式。請參閱下面的格式選項。在大多數情況下,可以使用與 date() 相同的字母。

所有欄位皆以目前的日期/時間初始化。在大多數情況下,您會希望將它們重置為「零」(Unix 紀元,1970-01-01 00:00:00 UTC)。您可以透過在 format 的第一個字元包含 ! 字元,或在最後包含 | 字元來完成此操作。請參閱下方每個字元的說明文件以取得更多資訊。

格式是從左到右解析的,這表示在某些情況下,格式字元出現的順序會影響結果。在 z(一年中的第幾天)的情況下,需要先解析年份,例如透過 Yy 字元。

用於解析數字的字母允許廣泛的值,超出邏輯範圍。例如,d(月份中的第幾天)接受 0099 範圍內的值。唯一的限制是位數。當給定超出範圍的值時,將使用日期/時間解析器的溢位機制。以下範例顯示了其中一些行為。

這也表示為格式字母解析的資料是貪婪的,它會讀取其格式允許的位數。這也可能表示 datetime 字串中沒有足夠的字元供後續的格式字元使用。此頁面上的一個範例也說明了這個問題。

format 參數字串中辨識以下字元
format 字元 說明 可解析值的範例
--- ---
dj 月份中的第幾天,2 位數字,可以有前導零,也可以沒有前導零 0131131。(大於一個月天數的兩位數也會被接受,此時月份會溢位。例如,一月使用 33 表示二月 2 日)
Dl 星期的文字表示法 MonSunSundaySaturday。如果給定的星期名稱與解析(或預設)日期的星期名稱不同,則會溢位至下一個具有給定星期名稱的日期。請參閱以下範例說明。
S 月份日期的英文序數後綴,2 個字元。處理時會被忽略。 stndrdth
z 一年中的第幾天(從 0 開始);必須以 Yy 作為前綴。 0365。(大於一年天數的三位數也會被接受,此時年份會溢位。例如,2022 年使用 366 表示 2023 年 1 月 2 日)
月份 --- ---
FM 月份的文字表示法,例如 January 或 Sept JanuaryDecemberJanDec
mn 月份的數字表示法,可包含或不包含前導零 0112112。(大於 12 的兩位數也會被接受,此時年份會溢位。例如,使用 13 表示下一年的 1 月)
年份 --- ---
Xx 年份的完整數字表示法,最多 19 位數,可選擇以 +- 作為前綴 範例:00557871999-2003+10191
Y 年份的完整數字表示法,最多 4 位數 範例:005578719992003
y 年份的兩位數表示法(假設範圍為 1970-2069,含) 範例:9903(將分別解讀為 19992003
時間 --- ---
aA 上午和下午 ampm
gh 12 小時制的小時數,可包含或不包含前導零 1120112(大於 12 的兩位數也會被接受,此時日期會溢位。例如,使用 14 表示下一個上午/下午時段的 02
GH 24 小時制,可包含或不包含前導零 0230023(大於 24 的兩位數也會被接受,此時會造成日期溢位。例如,使用 26 表示隔天的 02:00
i 分鐘,包含前導零 0059。(大於 59 的兩位數也會被接受,此時會造成小時溢位。例如,使用 66 表示下一個小時的 :06
s 秒鐘,包含前導零 0059(大於 59 的兩位數也會被接受,此時會造成分鐘溢位。例如,使用 90 表示下一分鐘的 :30
v 毫秒的小數部分(最多三位數) 範例:120.12 秒),3450.345 秒)
u 微秒的小數部分(最多六位數) 範例:450.000045 秒),6543210.654321 秒)
時區 --- ---
eOpPT 時區識別碼、與 UTC 的小時差、以冒號分隔小時和分鐘的與 UTC 的時差,或時區縮寫 範例:UTCGMTAtlantic/Azores+0200+02:00ESTMDT
完整的日期/時間 --- ---
U 自 Unix 紀元(1970 年 1 月 1 日 00:00:00 GMT)以來的秒數 範例:1292177455
空白和分隔符號 --- ---
(空格) 零個或多個空格、定位鍵、不換行空格 (U+A0) 或窄不換行空格 (U+202F) 字元 範例:"\t"" "
# 下列分隔符號之一:;:/.,-() 範例:/
;:/.,-() 指定的字元。 範例:-
? 隨機位元組 範例:^(請注意,對於 UTF-8 字元,您可能需要多個 ?。在這種情況下,使用 * 可能是您想要的)
* 隨機位元組,直到下一個分隔符號或數字 範例:在字串 2009-aWord-08 中,使用 Y-*-d 中的 * 將會匹配 aWord
! 將所有欄位(年、月、日、小時、分鐘、秒、小數和時區資訊)重設為類似零的值(小時、分鐘、秒和小數為 0,月和日為 1,年為 1970,時區資訊為 UTC 如果沒有 !,所有欄位將會設定為目前的日期和時間。
| 如果尚未解析,則會將所有欄位(年、月、日、時、分、秒、小數和時區資訊)重置為類似零的值。 Y-m-d| 會將年、月和日設定為在要解析的字串中找到的資訊,並將時、分和秒設定為 0。
+ 如果存在此格式指定符,則字串中的尾端數據不會導致錯誤,而是發出警告。 使用 DateTimeImmutable::getLastErrors() 來查明是否存在尾端數據。

格式字串中無法識別的字元將導致解析失敗,並將錯誤訊息附加到返回的結構。您可以使用 DateTimeImmutable::getLastErrors() 查詢錯誤訊息。

要在 format 中包含字面字元,您必須使用反斜線 (\) 對其進行跳脫。

如果 format 不包含字元 !,則在 format 中未指定的已產生日期/時間的部分將設定為目前的系統時間。

如果 format 包含字元 !,則在 format 中未提供的已產生日期/時間的部分,以及 ! 左側的值,將設定為 Unix 紀元中的對應值。

如果解析了任何時間字元,則所有其他與時間相關的欄位都設定為「0」,除非也已解析。

Unix 紀元是 1970-01-01 00:00:00 UTC。

datetime

表示時間的字串。

timezone

表示所需時區的 DateTimeZone 物件。

如果省略 timezone 或為 nulldatetime 不包含時區,則將使用目前的時區。

注意事項:

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 已新增 Xx format 指定符。
8.0.21, 8.1.8, 8.2.0 現在,當將 NULL 位元組傳遞到 datetime 時會擲出 ValueError,以前會忽略此情況。
7.3.0 已新增 v format 指定符。

範例

範例 #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 個數字。因為後面有兩個數字,它會貪婪地讀取為 60

後面的格式字元 is 都需要兩個數字。這表示 10 會被當作分鐘 (i) 傳遞,然後就沒有足夠的數字可以解析為秒數 (s) 了。

errors 陣列會指出這個問題。

此外,60 的時數超出 0-24 的範圍,這會導致 warnings 陣列包含一個時間無效的警告。

另請參閱

新增筆記

使用者貢獻的筆記 3 則筆記

1
Andy Walker
2 年前
要澄清一下,g/G 是 12/24 小時制 tanpa angka nol di depan,而 h/H 是 12/24 小時制 dengan angka nol di depan,如此處所述

https://php.dev.org.tw/manual/en/datetime.format.php
1
Tessa at AuRiseCreative dot com
10 個月前
由於時區列的說明和範例並不完全相符,我想釐清每個字元輸出的確切格式。

`e` 輸出時區識別碼,例如 `America/New_York` 或 `Asia/Gaza`

`O` 輸出與 UTC 的時差(以小時為單位),例如 `-0500` 或 `+0200`

`P` 輸出與 UTC 的時差,小時和分鐘之間以冒號分隔,例如 `-05:00` 或 `+02:00`

`T` 輸出時區縮寫,例如 `EST` 或 `EET`
0
peter dot labos at gmail dot com
10 個月前
如果您不滿意此方法為您進行的大範圍轉換和修復,或者只想檢查日期是否與輸入的日期完全相同

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

if ($datetime && $datetime->format('Y-m-d G:i:s') === $userDateTimeInput) {
// $datetime 不是 false,而且我們從使用者那裡得到了格式正確的日期
}
```
To Top