为了澄清,g/G 是 12/24 小时制时间,不带前导 0,h/H 是 12/24 小时制时间,带前导零,如下所述
https://php.net/manual/en/datetime.format.php
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
DateTimeImmutable::createFromFormat -- date_create_immutable_from_format — 根据指定格式解析时间字符串
面向对象风格
$format
, string $datetime
, ?DateTimeZone $timezone
= null
): DateTimeImmutable|false过程式风格
$format
, string $datetime
, ?DateTimeZone $timezone
= null
): DateTimeImmutable|false返回一个新的 DateTimeImmutable 对象,该对象表示由 datetime
字符串指定的日期和时间,该字符串以给定的 format
格式化。
format
传递的 string 应该具有的格式。请参阅下面的格式选项。在大多数情况下,可以使用与 date() 相同的字母。
所有字段都用当前日期/时间初始化。在大多数情况下,您可能希望将其重置为“零”(Unix 纪元,1970-01-01 00:00:00 UTC
)。您可以通过在 format
中的第一个字符中包含 !
字符,或在最后一个字符中包含 |
来实现。有关更多信息,请参阅下面每个字符的文档。
格式从左到右解析,这意味着在某些情况下,格式字符出现的顺序会影响结果。在 z
(年中的某一天)的情况下,需要先解析年份,例如通过 Y
或 y
字符。
用于解析数字的字母允许广泛的值范围,超出逻辑范围。例如,d
(月份中的某一天)接受 00
到 99
范围内的值。唯一限制是数字的数量。当给出超出范围的值时,将使用日期/时间解析器的溢出机制。下面的示例展示了其中的一些行为。
这也意味着为格式字母解析的数据是贪婪的,并且会读取其格式允许的位数。然后这也可能意味着 datetime
字符串中没有足够的字符用于以下格式字符。本页的一个示例也说明了这个问题。
format 字符 |
描述 | 示例可解析的值 |
---|---|---|
日 | --- | --- |
d 和 j |
月份中的某一天,两位数,有或没有前导零 |
01 到 31 或 1 到 31 。 (大于一个月中的天数的两位数被接受,在这种情况下它们会导致月份溢出。例如,将 33 与 1 月一起使用,表示 2 月 2 日) |
D 和 l |
一天的文本表示 |
Mon 到 Sun 或 Sunday 到 Saturday 。如果给定的日期名称与解析(或默认)日期的日期名称不同,则会发生溢出到具有给定日期名称的下一个日期。有关说明,请参见下面的示例。 |
S |
月份中的某一天的英文序数后缀,两位数。在处理过程中,它被忽略。 |
st 、nd 、rd 或 th 。 |
z |
年中的某一天(从 0 开始);必须在 Y 或 y 之前。 |
0 到 365 。 (三位数大于一年中的数字被接受,在这种情况下它们会导致年份溢出。例如,将 366 与 2022 一起使用,表示 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 表示下一个 AM/PM 周期的 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.45 秒)、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 |
空格和分隔符 | --- | --- |
(空格) |
零个或多个空格、制表符、NBSP(U+A0)或 NNBSP(U+202F)字符 | 示例:"\t" 、" " |
# |
以下分隔符之一:; 、: 、/ 、. 、, 、- 、( 或 ) |
示例:/ |
; , : , / , . , , , - , ( 或 ) |
指定的字符。 | 示例:- |
? |
一个随机字节 | 示例:^ (注意,对于 UTF-8 字符,您可能需要使用多个 ? 。在这种情况下,使用 * 可能更合适) |
* |
从当前位置到下一个分隔符或数字的随机字节 | 示例:在 Y-*-d 中使用 * ,字符串为 2009-aWord-08 ,则将匹配 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
包含空字节时,此方法将抛出 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 | 现在,当 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 小时制时间,不带前导 0,h/H 是 12/24 小时制时间,带前导零,如下所述
https://php.net/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 不为假,并且我们从用户那里获得了正确格式的正确日期
}
```