编辑:
class ComparableDateInterval extends DateInterval
{
/**
* Leap-year safe comparison of DateInterval objects.
*/
public function compare(DateInterval $oDateInterval)
{
$fakeStartDate1 = date_create();
$fakeStartDate2 = clone $fakeStartDate1;
$fakeEndDate1 = $fakeStartDate1->add($this);
$fakeEndDate2 = $fakeStartDate2->add($oDateInterval);
if($fakeEndDate1 < $fakeEndDate2) {
return -1;
} elseif($fakeEndDate1 == $fakeEndDate2) {
return 0;
}
return 1;
}
}
$int15 = new ComparableDateInterval('P15D');
$int20 = new ComparableDateInterval('P20D');
var_dump($int15->compare($int20) == -1); // should be true;
请参阅@fyrye 的答案以了解基本原理(并支持它!)。我最初的答案没有安全地处理闰年。
原始答案
虽然我赞成这个问题,但我反对接受的答案。那是因为它对我的任何 PHP 安装都不起作用,而且从根本上说它取决于内部损坏的东西。
相反,我所做的是迁移上述从未将其放入主干的补丁。FWIW 我检查了最近的版本PHP 5.6.5,但补丁仍然不存在。代码很容易移植。唯一的问题是它如何进行比较的警告
如果已经计算了 $this->days,我们知道它是准确的,所以我们将使用它。如果不是,我们需要对月份和年份长度做出假设,这不一定是一个好主意。我已经完全凭空将月定义为 30 天,将年定义为 365 天,因为我没有可用的 ISO 8601 规范来检查是否存在标准假设,但实际上如果我们没有,我们可能想出错'没有 $this->days 可用。
这是一个例子。请注意,如果您需要比较DateInterval
从其他调用返回的create
a ComparableDateInterval
,如果您想将其用作比较的源,则必须首先从它中获取。
$int15 = new ComparableDateInterval('P15D');
$int20 = new ComparableDateInterval('P20D');
var_dump($int15->compare($int20) == -1); // should be true;
这是代码
/**
* The stock DateInterval never got the patch to compare.
* Let's reimplement the patch in userspace.
* See the original patch at http://www.adamharvey.name/patches/DateInterval-comparators.patch
*/
class ComparableDateInterval extends DateInterval
{
static public function create(DateInterval $oDateInterval)
{
$oDi = new ComparableDateInterval('P1D');
$oDi->s = $oDateInterval->s;
$oDi->i = $oDateInterval->i;
$oDi->h = $oDateInterval->h;
$oDi->days = $oDateInterval->days;
$oDi->d = $oDateInterval->d;
$oDi->m = $oDateInterval->m;
$oDi->y = $oDateInterval->y;
$oDi->invert = $oDateInterval->invert;
return $oDi;
}
public function compare(DateInterval $oDateInterval)
{
$oMyTotalSeconds = $this->getTotalSeconds();
$oYourTotalSeconds = $oDateInterval->getTotalSeconds();
if($oMyTotalSeconds < $oYourTotalSeconds)
return -1;
elseif($oMyTotalSeconds == $oYourTotalSeconds)
return 0;
return 1;
}
/**
* If $this->days has been calculated, we know it's accurate, so we'll use
* that. If not, we need to make an assumption about month and year length,
* which isn't necessarily a good idea. I've defined months as 30 days and
* years as 365 days completely out of thin air, since I don't have the ISO
* 8601 spec available to check if there's a standard assumption, but we
* may in fact want to error out if we don't have $this->days available.
*/
public function getTotalSeconds()
{
$iSeconds = $this->s + ($this->i * 60) + ($this->h * 3600);
if($this->days > 0)
$iSeconds += ($this->days * 86400);
// @note Maybe you prefer to throw an Exception here per the note above
else
$iSeconds += ($this->d * 86400) + ($this->m * 2592000) + ($this->y * 31536000);
if($this->invert)
$iSeconds *= -1;
return $iSeconds;
}
}