Commit 5f9eb6db8ab for php.net
commit 5f9eb6db8abd71c5226bf1142fe0752f6405719d
Author: Tim Düsterhus <tim@bastelstu.be>
Date: Wed Sep 16 09:26:50 2026 +0200
date: Add comparison handler to Time\Duration (#23695)
As stated in the RFC:
> The Time\Duration class will also implement internal “comparison handlers”,
> which means that direct comparisons with operators such as < will work.
> Other operators (such as + for addition) will not be overloaded.
diff --git a/NEWS b/NEWS
index d6e5c03d331..4d0f0ae5907 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ PHP NEWS
- Date:
. Fix unserialization of Time\Duration. (timwolla)
+ . Add comparison handler for Time\Duration. (timwolla)
- DOM:
. Fixed use-after-free when re-constructing a DOMXPath whose php:function
diff --git a/ext/date/php_time.c b/ext/date/php_time.c
index 2c3698f63fb..41f2673eafe 100644
--- a/ext/date/php_time.c
+++ b/ext/date/php_time.c
@@ -48,6 +48,13 @@ static zend_object *time_duration_object_clone(zend_object *object)
return &new_obj->std;
}
+static int time_duration_object_compare(zval *a, zval *b)
+{
+ ZEND_COMPARE_OBJECTS_FALLBACK(a, b);
+
+ return timelib_duration_compare(&Z_DATE_TIME_DURATION_P(a)->duration, &Z_DATE_TIME_DURATION_P(b)->duration);
+}
+
PHP_MINIT_FUNCTION(date_time)
{
/* Time\TimeException */
@@ -57,6 +64,7 @@ PHP_MINIT_FUNCTION(date_time)
memcpy(&time_duration_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
time_duration_object_handlers.offset = offsetof(php_date_time_duration, std);
time_duration_object_handlers.clone_obj = time_duration_object_clone;
+ time_duration_object_handlers.compare = time_duration_object_compare;
php_date_ce_time_duration = register_class_Time_Duration();
php_date_ce_time_duration->create_object = time_duration_object_create;
php_date_ce_time_duration->default_object_handlers = &time_duration_object_handlers;
diff --git a/ext/date/tests/time/duration/compare.phpt b/ext/date/tests/time/duration/compare.phpt
new file mode 100644
index 00000000000..fd0f5d9002c
--- /dev/null
+++ b/ext/date/tests/time/duration/compare.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Time\Duration: Comparison handlers
+--FILE--
+<?php
+
+require __DIR__ . '/helper.inc';
+
+$durations = [
+ Time\Duration::fromSeconds(0, 0),
+ Time\Duration::fromSeconds(0, 1),
+ Time\Duration::fromSeconds(0, 2),
+ Time\Duration::fromSeconds(1, 0),
+ Time\Duration::fromSeconds(1, 1),
+ Time\Duration::fromSeconds(1, 2),
+ Time\Duration::fromSeconds(2, 0),
+ Time\Duration::fromSeconds(2, 1),
+ Time\Duration::fromSeconds(2, 2),
+];
+
+function n(int $result) {
+ return ($result === 0 ? '=' : ($result < 0 ? '<' : '>'));
+}
+
+$durations = [
+ ...$durations,
+ null,
+ ...negate_all($durations),
+];
+
+foreach ($durations as $a) {
+ if ($a === null) {
+ continue;
+ }
+
+ foreach ($durations as $b) {
+ if ($b === null) {
+ continue;
+ }
+
+ if (n($a <=> $b) !== n(Time\Duration::compare($a, $b))) {
+ echo sprintf('%1$s <=> %2$s !== Duration::compare(%1$s, %2$s)', f($a, pad: false), f($b, pad: false)), PHP_EOL;
+ }
+ }
+}
+
+?>
+==DONE==
+--EXPECT--
+==DONE==