This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new 9288e2c95 Fix the overflow bound direction in 
Instants.toMillisSince(Instant) (#1766)
9288e2c95 is described below

commit 9288e2c95f39abd1ff115aeddafaa276ceafae6d
Author: renechoi <[email protected]>
AuthorDate: Tue Aug 4 20:51:35 2026 +0900

    Fix the overflow bound direction in Instants.toMillisSince(Instant) (#1766)
    
    The Javadoc states that a result greater than Long.MAX_VALUE is bound to
    Long.MAX_VALUE and one lesser than Long.MIN_VALUE to Long.MIN_VALUE, but the
    bound was selected from the sign of the instant's epoch second. The value 
being
    bound is the duration from that instant to now, whose sign is the opposite, 
so
    both reachable overflow cases returned the wrong end: Instant.MIN gave
    Long.MIN_VALUE where the contract asks for Long.MAX_VALUE, and Instant.MAX 
the
    reverse.
    
    Bind on the sign of the duration instead. The two tests that pinned the 
previous
    behavior are updated; both fail without this change.
---
 .../java/org/apache/commons/lang3/time/Instants.java   |  9 ++++++---
 .../org/apache/commons/lang3/time/InstantsTest.java    | 18 ++++++++----------
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/time/Instants.java 
b/src/main/java/org/apache/commons/lang3/time/Instants.java
index 8532afaf9..094cb4319 100644
--- a/src/main/java/org/apache/commons/lang3/time/Instants.java
+++ b/src/main/java/org/apache/commons/lang3/time/Instants.java
@@ -17,6 +17,7 @@
 
 package org.apache.commons.lang3.time;
 
+import java.time.Duration;
 import java.time.Instant;
 
 /**
@@ -86,11 +87,13 @@ public static Instant toInstant(final Instant instant, 
final Instant defaultInst
      * @return long The duration in milliseconds since the given Instant.
      */
     public static long toMillisSince(final Instant instant) {
-        final Instant instant2 = toInstant(instant);
+        // The sign of the duration is the opposite of the sign of the 
instant's epoch second: an instant far in the past
+        // yields a large positive duration, an instant far in the future a 
large negative one. Bind on the duration.
+        final Duration duration = DurationUtils.since(toInstant(instant));
         try {
-            return DurationUtils.since(instant2).toMillis();
+            return duration.toMillis();
         } catch (final ArithmeticException e) {
-            return toBound(instant2, Long.MIN_VALUE, Long.MAX_VALUE);
+            return duration.isNegative() ? Long.MIN_VALUE : Long.MAX_VALUE;
         }
     }
 
diff --git a/src/test/java/org/apache/commons/lang3/time/InstantsTest.java 
b/src/test/java/org/apache/commons/lang3/time/InstantsTest.java
index 0a7bfdb9f..1da258747 100644
--- a/src/test/java/org/apache/commons/lang3/time/InstantsTest.java
+++ b/src/test/java/org/apache/commons/lang3/time/InstantsTest.java
@@ -179,23 +179,21 @@ void testToMillisSinceFutureInstantIsNegative() {
     }
 
     /**
-     * {@link Instant#MAX} (positive epoch second): the huge negative duration 
from Instant.MAX to now
-     * overflows {@code long} millis; the bound is {@link Long#MAX_VALUE} 
because the instant's epoch
-     * second is positive.
+     * {@link Instant#MAX} is in the future, so the duration from it to now is 
negative and underflows {@code long}
+     * millis; the bound is {@link Long#MIN_VALUE}.
      */
     @Test
-    void testToMillisSinceInstantMaxOverflowReturnsMaxValue() {
-        assertEquals(Long.MAX_VALUE, Instants.toMillisSince(Instant.MAX));
+    void testToMillisSinceInstantMaxUnderflowReturnsMinValue() {
+        assertEquals(Long.MIN_VALUE, Instants.toMillisSince(Instant.MAX));
     }
 
     /**
-     * {@link Instant#MIN} (negative epoch second): the huge positive duration 
from Instant.MIN to now
-     * overflows {@code long} millis; the bound is {@link Long#MIN_VALUE} 
because the instant's epoch
-     * second is negative.
+     * {@link Instant#MIN} is in the past, so the duration from it to now is 
positive and overflows {@code long}
+     * millis; the bound is {@link Long#MAX_VALUE}.
      */
     @Test
-    void testToMillisSinceInstantMinOverflowReturnsMinValue() {
-        assertEquals(Long.MIN_VALUE, Instants.toMillisSince(Instant.MIN));
+    void testToMillisSinceInstantMinOverflowReturnsMaxValue() {
+        assertEquals(Long.MAX_VALUE, Instants.toMillisSince(Instant.MIN));
     }
 
     /**

Reply via email to