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

过程化风格

返回一个新的 DateTimeImmutable 对象,该对象表示由 datetime 字符串指定的日期和时间,该字符串以给定的 format 格式化。

参数

format

传递的 string 应采用的格式。请参阅下面的格式选项。在大多数情况下,可以使用与 date() 相同的字母。

所有字段都使用当前日期/时间初始化。在大多数情况下,您希望将其重置为“零”(Unix 纪元,1970-01-01 00:00:00 UTC)。您可以通过在 format 中将 ! 字符作为第一个字符或 | 作为最后一个字符来实现。有关更多信息,请参阅下面每个字符的文档。

格式从左到右解析,这意味着在某些情况下,格式字符出现的顺序会影响结果。在 z(一年中的某一天)的情况下,需要已经解析了一年,例如通过 Yy 字符。

用于解析数字的字母允许使用各种范围的值,超出逻辑范围。例如,d(一个月中的某一天)接受 0099 范围内的值。唯一的约束是数字的数量。当给出超出范围的值时,将使用日期/时间解析器的溢出机制。下面的示例显示了一些此类行为。

这也意味着为格式字母解析的数据是贪婪的,并且将读取其格式允许的最多位数字。然后,这可能也意味着 datetime 字符串中不再有足够的字符供后续的格式字符使用。此页面上的一个示例也说明了此问题。

format 参数字符串中识别以下字符
format 字符 描述 示例可解析值
--- ---
dj 一个月中的某一天,两位数,带或不带前导零 0131131。(两位数大于一个月中的天数是可以接受的,在这种情况下,它们将使月份溢出。例如,在 1 月使用 33 表示 2 月 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 表示下一个 AM/PM 周期的 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.45 秒),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 字符,您可能需要多个 ?。在这种情况下,使用 * 可能是您想要的)
* 直到下一个分隔符或数字的随机字节 例如:在 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。

日期时间

表示时间的字符串。

时区

一个表示所需时区的 DateTimeZone 对象。

如果省略了 timezone 或为 null 并且 datetime 不包含时区,则将使用当前时区。

注意:

datetime 参数包含 UNIX 时间戳(例如 946684800)或指定时区(例如 2010-01-28T15:00:00+02:00)时,将忽略 timezone 参数和当前时区。

返回值

返回一个新的 DateTimeImmutable 实例或在失败时返回 false

错误/异常

datetime 包含空字节时,此方法会抛出 ValueError

变更日志

版本 描述
8.2.9 (空格)说明符现在还支持不间断空格 (U+A0) 和窄不间断空格 (U+202F) 字符。
8.2.0 已添加 Xx 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 '当前时间: ' . date('Y-m-d H:i:s') . "\n";

$format = 'Y-m-d';
$date = DateTimeImmutable::createFromFormat($format, '2009-02-15');
echo
"格式: $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; " . $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; " . $date->format('Y-m-d H:i:s') . "\n";

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

$format = 'i';
$date = DateTimeImmutable::createFromFormat($format, '15');
echo
"格式: $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 条注释

Andy Walker
2 年前
澄清一下,g/G 是不带前导 0 的 12/24 小时制时间,h/H 是带前导零的 12/24 小时制时间,如下所述

https://php.net/manual/en/datetime.format.php
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`
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 不为假,并且我们从用户那里得到了正确格式的正确日期
}
```
To Top