为啥“YYYY-MM-DD”日期格式的两个字符串在PHP中的小于或大于比较工作,即使它们是字符串?

Posted

技术标签:

【中文标题】为啥“YYYY-MM-DD”日期格式的两个字符串在PHP中的小于或大于比较工作,即使它们是字符串?【英文标题】:Why does a less than or more than comparison in PHP of two strings in the date format of "YYYY-MM-DD" work even though they are strings?为什么“YYYY-MM-DD”日期格式的两个字符串在PHP中的小于或大于比较工作,即使它们是字符串? 【发布时间】:2013-06-26 15:27:40 【问题描述】:

我正在为一个项目编写一段 php 代码,它将 YYYY-MM-DD 格式的日期与当前日期进行比较,以查看它是否小于当前日期。在代码的不同点,使用了两种不同的方法进行比较。第一个在日期上使用get_timestamp() 并根据时间戳进行比较。在另一个地方,它只是将日期字符串与date("Y-m-d") 的输出进行比较。我的期望是两个日期字符串的比较不会提供正确的响应。但是,当我设置几个测试用例时,我得到了预期的输出。我查看了 PHP 手册的两部分以获得洞察力,但我仍然对为什么在没有转换为时间戳的情况下进行比较感到困惑。

PHP 手册的comparison operators 部分指出,字符串要么被转换为数字,然后进行数字比较,要么进行所谓的词法比较。我找不到更多关于词法比较的信息,但是当我阅读有关 string conversion to numbers 并尝试使用日期字符串的示例时,我尝试的每个日期字符串都会得到相同的数字输出。

谁能帮我理解为什么两个日期字符串的大于或小于比较有效(或至少看起来有效)?我错过了什么?

作为后续,如果它确实有效,我认为将日期转换为时间戳并根据时间戳进行比较是一种更好的做法。将日期转换为时间戳的更好功能是:get_timestamp()strtotime()

两个YYYY-MM-DD字符串的小于/大于比较示例代码:

if ("2013-06-27" < "2013-06-28")  echo "less";  // Output: less
if ("2013-06-27" > "2013-06-28")  echo "more";  // Output: (none)

if ("2013-06-29" < "2013-06-28")  echo "less";  // Output: (none)
if ("2013-06-29" > "2013-06-28")  echo "more";  // Output: more

测试转换后的 YYYY-MM-DD 字符串的数值的示例代码

$foo = 1 + "2013-06-27";
echo "\$foo==$foo"; // Output: $foo = 2014
$foo = 1 + "2013-06-28";
echo "\$foo==$foo"; // Output: $foo = 2014
$foo = 1 + "2013-06-29";
echo "\$foo==$foo"; // Output: $foo = 2014

【问题讨论】:

“我认为将日期转换为时间戳并根据时间戳进行比较是一种更好的做法” - 为什么?我想不出这是真的原因。只要格式正确(YYYY-MM-DD 或类似),比较字符串日期就没有问题。要回答您的一个问题,strtotime 接受一个字符串,而 get_timestamp 接受一个 DateTime 对象。所以这取决于。我发现自己很少使用 DateTime 对象,因为 php 具有出色的功能,例如 strtotime 来处理日期字符串。 我认为对两个日期字符串使用简单的小于或大于比较不是最佳实践,因为我看到的所有其他日期比较示例首先将其转换为时间戳。如果您不必这样做,将其转换为时间戳似乎确实是一个额外的步骤。 显然是因为,如果你去掉标点符号,它们是......本质上是numbers :) 你比较数字...... 转换为时间戳还有其他充分的理由,例如执行计算(减去日期、添加/减去时间段)和处理时区问题。但是这种比较特性是这种特殊字符串表示在计算机应用程序中流行的原因之一。 值得一提的是,您在上面的示例表达式中得到2014 的原因是,当对字符串进行算术运算时,PHP 会遍历您的字符串以查找通过ctype_digit() 的字符函数并在第一个无数字字符处停止。因此,将上述日期转换为 int 会返回 2013,然后添加 1 以得到 2014 【参考方案1】:

这样比较一个字符串时,它会从左到右,比较给定字符串中的每个字符,看它们是否不同,直到找到不同之处,然后通过比较来决定哪个字符串更大最后一个字符的 ASCII 值。巧合的是,由于您只使用数字,因此 ASCII 表中的最高数字也更高。

只要您在比较中仅使用数字,并且每个字符串具有相同数量的字符,此解决方案就可以工作

另请注意,这仅在您使用 YYYY-MM-DD 格式时才有效,如果您使用其他格式,它将不起作用。

【讨论】:

感谢您的回复。那么,每个字符从左到右的比较是不是“词法比较”的意思? @PeterA - 一个老点,但是是的。请注意,LTR(从左到右)语言中的数字在开始时用最高数量级的数字表示(例如,单位前的百前十)。时间通常也以这种方式表示。但是,大多数西方日期格式不遵循相同的习惯,其中一些 (m/d/Y) 实际上没有遵循特定的数量级。这已针对 ISO 8601 进行了更正。对于未来比较的一般指导,我建议使用 DateTimeInterface 类之一。 但是为什么 - 字符不干扰比较呢?是因为它们在两个字符串中相等吗? @billrichards 是的【参考方案2】:

使用DateTime 类来比较日期。它使它更容易理解,并且您不必处理类型杂耍。

【讨论】:

以上是关于为啥“YYYY-MM-DD”日期格式的两个字符串在PHP中的小于或大于比较工作,即使它们是字符串?的主要内容,如果未能解决你的问题,请参考以下文章

PHP:以YYYY-MM-DD格式获取两个日期之间的天数[重复]

两个日期之间相差的天数

如何在presto sql中将字符串'yyyy-mm-dd'转换为日期格式

计算两个日期之间相差的天数(带带负数) 支持格式YYYY-mm-dd比较

Python - 以 YYYY-MM-DD 格式获取昨天的日期作为字符串

怎么将YYYYMMDD字符串格式转换为日期YYYY-MM-DD