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));
}
/**