EDIT:
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-> дней доступно.
Вот пример. Обратите внимание: если вам нужно сравнить 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;
}
}