PHP DateTime::createFromFormat的行为表现

7
今天,我在使用 \DateTime::createFromFormat 函数时遇到了一些困惑。
我的情况是,我有一个字符串,表示以下格式的日期: m/Y (05/2017)。当我想将字符串转换为 DateTime 对象时,我遇到了以下问题: $date = \DateTime::createFromFormat('m/Y', '02/2017'); 当我输出 $date 变量时,其中的日期属性是 '2017-03-03 11:06:36.000000' 但如果我在月份之前添加日期,例如:$date = \DateTime::createFromFormat('d/m/Y', '01/02/2017');,则会返回具有正确日期属性的对象。(不幸的是,我不能更改日期格式并添加日期。它必须是 m/Y)。
我想到的解决方法是将该月的第一天与我有的日期字符串连接起来,如:$date = '01/'.$dateString;,但我不想这样做,因为它是硬编码的。
这里出了什么问题?createFromFormat 函数缺少创建对象的信息吗?我对此感到非常困惑。谢谢大家的帮助!

这只是创建对象,var_dump $date->format()(格式与日期相同,因此仍适用于Y-m-d等),您应该看到您期望的结果 :) - treyBake
1
它会用今天的数据(第31天)填充缺失的数据,并调整以跳过无效日期。就像大多数PHP日期函数一样,这很有帮助。 - Álvaro González
2个回答

14

PHP默认会使用当前日期/时间的值填充缺失的日期值;因此

$date = \DateTime::createFromFormat('m/Y', '02/2017');

将丢失的日期值用当前日期填充;由于2月31日是无效日期,因此它将滚动到3月。同样,基于当前时间,缺少的小时/分钟/秒钟将被填充。

如果您想要强制开始于月初/时间,请在您的掩码前加上一个前导 !

$date = \DateTime::createFromFormat('!m/Y', '02/2017');

这将使用该月的第一天填充缺失的日期,时间将被填充为00:00:00

另外,末尾的|也会产生相同的效果

$date = \DateTime::createFromFormat('m/Y|', '02/2017');

非常感谢您的回答。这是我下次会知道的事情 :) - Whiplash
1
“!”和“|”的语法非常棒,而且似乎已经存在了相当长的时间(https://3v4l.org/YvIkt)。 - Álvaro González
2
阅读确切规格是很有趣的,可以理解!|代码的工作原理。基本上,它们将值设置为Unix Epoch - 我们得到第一天,因为它恰好是1970年1月1日00:00:00 UTC。 - Álvaro González

1
您不能存储不完整的日期,至少不能在专门用于复杂日期计算的日期格式中存储(但这并不妨碍您创建自己的MonthYear类)。因此,当您使用不完整信息创建DateTime()对象时,需要发生以下情况:
  • 崩溃
  • 使用某些默认值
PHP选择第二个选项,并做出了从C语言日期库继承的决定:
  1. 假设缺少的数据意味着“现在”
  2. 尝试自动修复此算法可能创建的无效日期
在这种情况下,“Feb 2017”变成了“31 Feb 2017”(因为“现在”是“31 May 2017”),PHP遵循这种推理:2017年2月只有28天,但我有三天多余;用户可能想将这三天多余的移动到三月。因此是“3 Mar 2017”。
我认为没有理由避免硬编码01,因为毕竟它是一个硬编码值(为什么是月份的第一天而不是最后一天或其他任何一天?)。
$input = '05/2017';
$date = \DateTime::createFromFormat('d/m/Y', "01/$input");

感谢您对功能的详细解释!问题是我总是试图避免硬编码值,但这次似乎PHP也在做同样的事情。我猜硬编码'01'就像在上面的答案中解释的添加'!m/Y'一样。 - Whiplash
基本上是这样。但是直到今天我才知道你可以使用 ! - Álvaro González
我的意思是Mark Baker的回答建议使用!,结果证明它确实可以做到同样的事情 :) 再次非常感谢。 - Whiplash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接