要澄清一下,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
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
DateTimeImmutable::createFromFormat -- date_create_immutable_from_format — 根據指定的格式解析時間字串
物件導向風格
$format
, 字串 $datetime
, ?DateTimeZone $timezone
= null
): DateTimeImmutable|false程序式風格
$format
, 字串 $datetime
, ?DateTimeZone $timezone
= null
): DateTimeImmutable|false傳回一個新的 DateTimeImmutable 物件,表示由 datetime
字串指定的日期和時間,該字串的格式為指定的 format
。
format
傳入的 字串 應使用的格式。請參閱下面的格式選項。在大多數情況下,可以使用與 date() 相同的字母。
所有欄位皆以目前的日期/時間初始化。在大多數情況下,您會希望將它們重置為「零」(Unix 紀元,1970-01-01 00:00:00 UTC
)。您可以透過在 format
的第一個字元包含 !
字元,或在最後包含 |
字元來完成此操作。請參閱下方每個字元的說明文件以取得更多資訊。
格式是從左到右解析的,這表示在某些情況下,格式字元出現的順序會影響結果。在 z
(一年中的第幾天)的情況下,需要先解析年份,例如透過 Y
或 y
字元。
用於解析數字的字母允許廣泛的值,超出邏輯範圍。例如,d
(月份中的第幾天)接受 00
到 99
範圍內的值。唯一的限制是位數。當給定超出範圍的值時,將使用日期/時間解析器的溢位機制。以下範例顯示了其中一些行為。
這也表示為格式字母解析的資料是貪婪的,它會讀取其格式允許的位數。這也可能表示 datetime
字串中沒有足夠的字元供後續的格式字元使用。此頁面上的一個範例也說明了這個問題。
format 字元 |
說明 | 可解析值的範例 |
---|---|---|
日 | --- | --- |
d 和 j |
月份中的第幾天,2 位數字,可以有前導零,也可以沒有前導零 |
01 至 31 或 1 至 31 。(大於一個月天數的兩位數也會被接受,此時月份會溢位。例如,一月使用 33 表示二月 2 日) |
D 和 l |
星期的文字表示法 |
Mon 至 Sun 或 Sunday 至 Saturday 。如果給定的星期名稱與解析(或預設)日期的星期名稱不同,則會溢位至下一個具有給定星期名稱的日期。請參閱以下範例說明。 |
S |
月份日期的英文序數後綴,2 個字元。處理時會被忽略。 |
st 、nd 、rd 或 th 。 |
z |
一年中的第幾天(從 0 開始);必須以 Y 或 y 作為前綴。 |
0 至 365 。(大於一年天數的三位數也會被接受,此時年份會溢位。例如,2022 年使用 366 表示 2023 年 1 月 2 日) |
月份 | --- | --- |
F 和 M |
月份的文字表示法,例如 January 或 Sept |
January 至 December 或 Jan 至 Dec |
m 和 n |
月份的數字表示法,可包含或不包含前導零 |
01 至 12 或 1 至 12 。(大於 12 的兩位數也會被接受,此時年份會溢位。例如,使用 13 表示下一年的 1 月) |
年份 | --- | --- |
X 和 x |
年份的完整數字表示法,最多 19 位數,可選擇以 + 或 - 作為前綴 |
範例:0055 、787 、1999 、-2003 、+10191 |
Y |
年份的完整數字表示法,最多 4 位數 | 範例:0055 、787 、1999 、2003 |
y |
年份的兩位數表示法(假設範圍為 1970-2069,含) | 範例:99 或 03 (將分別解讀為 1999 和 2003 ) |
時間 | --- | --- |
a 和 A |
上午和下午 | am 或 pm |
g 和 h |
12 小時制的小時數,可包含或不包含前導零 |
1 至 12 或 01 至 12 (大於 12 的兩位數也會被接受,此時日期會溢位。例如,使用 14 表示下一個上午/下午時段的 02 ) |
G 和 H |
24 小時制,可包含或不包含前導零 |
0 至 23 或 00 至 23 (大於 24 的兩位數也會被接受,此時會造成日期溢位。例如,使用 26 表示隔天的 02:00 ) |
i |
分鐘,包含前導零 |
00 至 59 。(大於 59 的兩位數也會被接受,此時會造成小時溢位。例如,使用 66 表示下一個小時的 :06 ) |
s |
秒鐘,包含前導零 |
00 至 59 (大於 59 的兩位數也會被接受,此時會造成分鐘溢位。例如,使用 90 表示下一分鐘的 :30 ) |
v |
毫秒的小數部分(最多三位數) | 範例:12 (0.12 秒),345 (0.345 秒) |
u |
微秒的小數部分(最多六位數) | 範例:45 (0.000045 秒),654321 (0.654321 秒) |
時區 | --- | --- |
e 、O 、p 、P 和 T |
時區識別碼、與 UTC 的小時差、以冒號分隔小時和分鐘的與 UTC 的時差,或時區縮寫 | 範例:UTC 、GMT 、Atlantic/Azores 或 +0200 或 +02:00 或 EST 、MDT |
完整的日期/時間 | --- | --- |
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
或為 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 | 已新增 X 和 x 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
雖然結果看起來很奇怪,但它是正確的,因為發生了以下溢位:
97
秒溢位到 1
分鐘,剩下 37
秒。
61
分鐘溢位到 1
小時,剩下 1
分鐘。
35
天溢位到 1
個月,剩下 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
雖然結果看起來很奇怪,但它是正確的,因為發生了以下溢位:
3 Aug 2020 25:00:00
會溢位成 (Tue) 4 Aug 2020 01:00
。
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
。
後面的格式字元 i
和 s
都需要兩個數字。這表示 10
會被當作分鐘 (i
) 傳遞,然後就沒有足夠的數字可以解析為秒數 (s
) 了。
errors
陣列會指出這個問題。
此外,60
的時數超出 0
-24
的範圍,這會導致 warnings
陣列包含一個時間無效的警告。
要澄清一下,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
由於時區列的說明和範例並不完全相符,我想釐清每個字元輸出的確切格式。
`e` 輸出時區識別碼,例如 `America/New_York` 或 `Asia/Gaza`
`O` 輸出與 UTC 的時差(以小時為單位),例如 `-0500` 或 `+0200`
`P` 輸出與 UTC 的時差,小時和分鐘之間以冒號分隔,例如 `-05:00` 或 `+02:00`
`T` 輸出時區縮寫,例如 `EST` 或 `EET`
如果您不滿意此方法為您進行的大範圍轉換和修復,或者只想檢查日期是否與輸入的日期完全相同
```
$datetime = \DateTimeImmutable::createFromFormat('Y-m-d G:i:s', $userDateTimeInput);
if ($datetime && $datetime->format('Y-m-d G:i:s') === $userDateTimeInput) {
// $datetime 不是 false,而且我們從使用者那裡得到了格式正確的日期
}
```