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==