如何在PHP 5.2.8中比较两个DateTime对象?

355

浏览PHP文档后,DateTime对象的以下两种方法都似乎可以解决我的问题:

这两种方法在doco中标记为版本 >= 5.3 可用(如果我尝试调用它们,我会发现它们不存在)。我找不到任何5.2.8的具体文档,因此不确定我的版本中是否有等效的方法。我已经Googled该问题并找到了各种各样的解决方案,但没有一个能满足我的简单要求:

  • 如何比较两个DateTime对象?
  • 在哪里可以找到先前PHP版本的文档?特别是版本5.2.8?

对于一些背景信息,我有以下代码:

$st_dt = new DateTime(verifyParam ('start_date'));
$end_dt = new DateTime(verifyParam ('end_date'));

// is the end date more ancient than the start date?
if ($end_dt < $start_dt) 

显然,这个人没有比较运算符。

编辑

显然,我的假设完全错误(感谢Milen的有效说明)。实际上有一个比较运算符,它很好用。有时候我真的想念编译器。错误在上面的代码中,我相信你会比我更快地找到它 :)。


1
关于缺少编译器 - 将 "error_reporting" 设置为 "E_ALL",您将收到类似于 "Notice: Undefined variable: start_dt in ..." 的通知。 - Milen A. Radev
5
请在您的$_POST变量上使用htmlentities,否则小猫将会被杀死。 - Clement Herreman
2
错误在哪里呢?:p ,我也在做这件事 U_U。谢谢提前! - castarco
2
@castarco 我初始化了 $st_dt,但是我与未初始化的 $start_dt 进行比较。请检查您的变量名称,并可能遵循 Milen 的建议将 error_reporting 设置为 E_ALL 以获取未定义变量警告。 :) - RedBlueThing
8个回答

505

下面的内容似乎证实了DateTime类有比较运算符:

dev:~# php
<?php
date_default_timezone_set('Europe/London');

$d1 = new DateTime('2008-08-03 14:52:10');
$d2 = new DateTime('2008-01-03 11:11:10');
var_dump($d1 == $d2);
var_dump($d1 > $d2);
var_dump($d1 < $d2);
?>
bool(false)
bool(true)
bool(false)
dev:~# php -v
PHP 5.2.6-1+lenny3 with Suhosin-Patch 0.9.6.2 (cli) (built: Apr 26 2009 20:09:03)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
dev:~#

10
谢谢你,Milen。看起来我只是需要去除我的错误假设,然后我代码中明显的漏洞就变得很明显了。 - RedBlueThing
3
这很有趣。也许在某个时候,我们将能够在用户定义的类中重载运算符。 - Ionuț G. Stan
11
比较一个没有设置小时的日期时间和一个设置了小时的日期时间时要注意(默认构造函数)。 - max4ever
1
TiMESPLiNTER,我相信警告是如果你只对比日期可能会忽略小时不同的事实,因此当你认为它们应该相等时,具有相同日期的两个DateTime将不会被比较为相等。您可以通过在比较之前显式将对象的时间组件设置为零来解决此问题。 - Jason
1
请记住,严格比较 (===) 比较的是对象,而不是值,因此在这种情况下它总是评估为 false。 - piotr_cz
显示剩余5条评论

101

官方文档

自PHP 5.2.2起,可以使用比较运算符来比较DateTime对象。

$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // false
var_dump($date1 < $date2); // true
var_dump($date1 > $date2); // false

对于 PHP 版本低于 5.2.2(实际上是任何版本),你可以使用 diff

$datetime1 = new DateTime('2009-10-11'); // 11 October 2013
$datetime2 = new DateTime('2009-10-13'); // 13 October 2013

$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days'); // +2 days

8
我觉得这个回答最好,因为它引用了手册而不是仅仅检查行为并假定结果符合预期。SO不是一个猜测的地方。干得好罗伯托。 - cprn
4
@roberto DateTime::diff 只在 PHP 5.3 中添加。 - NeXuS

35

19
请注意,format会产生一个字符串,因此这是一个字符串比较。在1000000000个时期时间之后(大约是2001年9月9日),这几乎不是问题,但如果你必须处理在此之前的日期,则可能会由于数字长度不同而遇到问题。要么将结果转换为数字(相减也可以),要么使用真正可排序的格式如 c - MaxArt
1
@MaxArt 能否详细说明由于字符串长度不同而导致的问题?关于数值上下文中的字符串,手册中指出:"如果字符串中不包含 '.', 'e' 或 'E' 字符,且数字值适合整型类型限制 (由 PHP_INT_MAX 定义),那么这个字符串将被解析为整数。在所有其他情况下,它将被解析为浮点数。" 未来日期(大约在2038年)可能会溢出有符号32位整数,但是旧日期有什么问题呢? - Adrian Günter
1
问题在于我们不会处于数字环境中,而是需要处理字符串。它们是数值,但仍然是字符串。因此将进行字符串比较。 - MaxArt
2
根据文档:如果您将数字与字符串进行比较或比较涉及数字字符串,则每个字符串都会转换为数字并进行数字比较。这些规则也适用于switch语句。当比较涉及类型和值时,不会进行类型转换,例如 === 或 !==。 - Frédéric Marchal
2
@FrédéricMarchal 是的,我后来确实了解到我之前的评论实际上是错误的。PHP有一种非常恶劣的处理这些情况的方式,没有其他语言(据我所知)在你有两个字符串要比较时将其转换为数字。如果您真的想进行词典比较,它会让您的代码出现问题。 - MaxArt
显示剩余2条评论

25

如果您想比较日期而非时间,可以使用这个:

$d1->format("Y-m-d") == $d2->format("Y-m-d")

6
你也可以设置重置时间。 $d1->setTime(0, 0, 0); - Athlan

1
$elapsed = '2592000';
// Time in the past
$time_past = '2014-07-16 11:35:33';
$time_past = strtotime($time_past);

// Add a month to that time
$time_past = $time_past + $elapsed;

// Time NOW
$time_now = time();

// Check if its been a month since time past
if($time_past > $time_now){
    echo 'Hasnt been a month';    
}else{
    echo 'Been longer than a month';
}

时间戳有一些限制,您可能想阅读这篇文章:http://stackoverflow.com/a/7229760/2652018 - Steel Brain
好的,知道了!这只是用于简单比较时间的一种方法。 - Kyle Coots

0
你提到了使用 DateTime::diff 来比较两个日期,你可以使用它来获得比布尔值更精确的值。
例如,获取天数:
$date1 = new DateTime('2021-07-09');
$date2 = new DateTime('2020-10-21');

echo $date1->diff($date2)->format('%R%a days');

但你也可以使用别名DateTime::diff,它是date_diff (PHP 5 >= 5.3.0, PHP 7, PHP 8)

$date1 = new DateTime('2021-07-09');
$date2 = new DateTime('2020-10-21');

echo date_diff($date1, $date2)->format('%R%a days');

-1
从PHP 7.x开始,您可以使用以下代码:
$aDate = new \DateTime('@'.(time()));
$bDate = new \DateTime('@'.(time() - 3600));

$aDate <=> $bDate; // => 1, `$aDate` is newer than `$bDate`

1
这个答案需要解释其不寻常的符号表示法[反斜杠和'@']以及它是如何工作的[将'@'与time()函数的结果连接起来]。 - Bilbo
4
答案需要包括任何不寻常符号的解释,例如反斜杠、At符号和太空船运算符。代码应包括有关如何工作的注释,例如:
  • 将 '@' 与 time() 的结果连接起来,可选择减去一小时的秒数
  • 实例化 DateTime 对象
  • 比较 DateTime 对象,如果相等则返回0,如果左值大于右值则返回1,如果右值大于左值则返回-1
- Bilbo

-2

这可能会对你有所帮助。

$today = date("m-d-Y H:i:s");
$thisMonth =date("m");
$thisYear = date("y");
$expectedDate = ($thisMonth+1)."-08-$thisYear 23:58:00";


if (strtotime($expectedDate) > strtotime($today)) {
    echo "Expected date is greater then current date";
    return ;
} else
{
 echo "Expected date is lesser then current date";
}

时间戳有一些限制,您可能想阅读这篇文章:http://stackoverflow.com/a/7229760/2652018 - Steel Brain
@SteelBrain,你认为时间戳限制会影响到以上代码吗?请再次阅读代码,它基本上是检查$expectedDate这个人,他将始终在当前月份。我不认为我们应该在这种情况下考虑时间戳限制。 - Tarun Gupta
我知道,但这不是推荐的方式。(我没有投反对票 :-) ) - Steel Brain
你能推荐一种推荐的方式吗? - Tarun Gupta
当然,$today = new DateTime("now"); $time = DateTime::createFromFormat('d-m-Y',"26-October-1998"); if ($today > $time){echo "今天更大";}else{echo "其他时间更大";} 干杯。 - Steel Brain

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