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 6e02b0a4d Add and use Instants.toInstant(Instant[, Instant]) (#1690)
6e02b0a4d is described below

commit 6e02b0a4d22f376a9414ff0a73f00ad9ef265241
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Jun 5 13:41:37 2026 -0400

    Add and use Instants.toInstant(Instant[, Instant]) (#1690)
---
 .../org/apache/commons/lang3/time/Instants.java    | 35 ++++++++--
 .../apache/commons/lang3/time/InstantsTest.java    | 77 ++++++++++++++++++++++
 2 files changed, 107 insertions(+), 5 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 2b28e89cd..2c3c23926 100644
--- a/src/main/java/org/apache/commons/lang3/time/Instants.java
+++ b/src/main/java/org/apache/commons/lang3/time/Instants.java
@@ -35,6 +35,7 @@ private static long toBound(final Instant instant, final long 
negBound, final lo
      * <ul>
      * <li>If the duration milliseconds are greater than {@link 
Long#MAX_VALUE}, then return {@link Long#MAX_VALUE}.</li>
      * <li>If the duration milliseconds are lesser than {@link 
Long#MIN_VALUE}, then return {@link Long#MIN_VALUE}.</li>
+     * <li>If the instant is null, treat it as {@link Instant#EPOCH}.</li>
      * </ul>
      *
      * @param instant The instant to convert, not null.
@@ -44,28 +45,52 @@ private static long toBound(final Instant instant, final 
long negBound, final lo
      * @see Long#MAX_VALUE
      */
     public static long toEpochMillis(final Instant instant) {
+        final Instant instant2 = toInstant(instant);
         try {
-            return instant.toEpochMilli();
+            return instant2.toEpochMilli();
         } catch (final ArithmeticException e) {
-            return toBound(instant, Long.MIN_VALUE, Long.MAX_VALUE);
+            return toBound(instant2, Long.MIN_VALUE, Long.MAX_VALUE);
         }
     }
 
     /**
-     * Converts an Instant to milliseconds sicne that Instant bound to a 
{@code long} without throwing {@link ArithmeticException}.
+     * Returns the given non-null instant, or {@link Instant#EPOCH} if null.
+     *
+     * @param instant the instant to test, may be null.
+     * @return the given non-null instant, or {@link Instant#EPOCH} if null.
+     */
+    public static Instant toInstant(final Instant instant) {
+        return toInstant(instant, Instant.EPOCH);
+    }
+
+    /**
+     * Returns the given non-null instant, or {@code defaultInstant} if 
instant is null.
+     *
+     * @param instant the instant to test, may be null.
+     * @param defaultInstant The default instant to use if the given instant 
is null, may be null.
+     * @return the given non-null instant, or {@code defaultInstant} if null.
+     */
+    public static Instant toInstant(final Instant instant, final Instant 
defaultInstant) {
+        return instant != null ? instant : defaultInstant;
+    }
+
+    /**
+     * Converts an Instant to milliseconds since that Instant bound to a 
{@code long} without throwing {@link ArithmeticException}.
      * <ul>
      * <li>If the duration milliseconds are greater than {@link 
Long#MAX_VALUE}, then return {@link Long#MAX_VALUE}.</li>
      * <li>If the duration milliseconds are lesser than {@link 
Long#MIN_VALUE}, then return {@link Long#MIN_VALUE}.</li>
+     * <li>If the instant is null, treat it as {@link Instant#EPOCH}.</li>
      * </ul>
      *
      * @param instant The instant to convert, not null.
      * @return long The duration in milliseconds since the given Instant.
      */
     public static long toMillisSince(final Instant instant) {
+        final Instant instant2 = toInstant(instant);
         try {
-            return DurationUtils.since(instant).toMillis();
+            return DurationUtils.since(instant2).toMillis();
         } catch (final ArithmeticException e) {
-            return toBound(instant, Long.MIN_VALUE, Long.MAX_VALUE);
+            return toBound(instant2, 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 365e12282..0a7bfdb9f 100644
--- a/src/test/java/org/apache/commons/lang3/time/InstantsTest.java
+++ b/src/test/java/org/apache/commons/lang3/time/InstantsTest.java
@@ -18,6 +18,8 @@
 package org.apache.commons.lang3.time;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.time.Instant;
@@ -80,6 +82,81 @@ void testToEpochMillisUnderflowReturnsMinValue() {
         assertEquals(Long.MIN_VALUE, Instants.toEpochMillis(INSTANT_FAR_PAST));
     }
 
+    @Test
+    void testToInstantEpochReturnsSameInstance() {
+        assertSame(Instant.EPOCH, Instants.toInstant(Instant.EPOCH));
+    }
+
+    @Test
+    void testToInstantMaxReturnsSameInstance() {
+        assertSame(Instant.MAX, Instants.toInstant(Instant.MAX));
+    }
+
+    @Test
+    void testToInstantMinReturnsSameInstance() {
+        assertSame(Instant.MIN, Instants.toInstant(Instant.MIN));
+    }
+
+    @Test
+    void testToInstantNonNullIsNotNull() {
+        assertNotNull(Instants.toInstant(Instant.now()));
+    }
+
+    @Test
+    void testToInstantNonNullReturnsSameInstance() {
+        final Instant now = Instant.now();
+        assertSame(now, Instants.toInstant(now));
+    }
+
+    @Test
+    void testToInstantNullReturnsEpoch() {
+        assertEquals(Instant.EPOCH, Instants.toInstant(null));
+    }
+
+    @Test
+    void testToInstantWithDefaultEpochReturnsSameInstance() {
+        assertSame(Instant.EPOCH, Instants.toInstant(Instant.EPOCH, 
Instant.MAX));
+    }
+
+    @Test
+    void testToInstantWithDefaultMaxReturnsSameInstance() {
+        assertSame(Instant.MAX, Instants.toInstant(Instant.MAX, Instant.MIN));
+    }
+
+    @Test
+    void testToInstantWithDefaultMinReturnsSameInstance() {
+        assertSame(Instant.MIN, Instants.toInstant(Instant.MIN, Instant.MAX));
+    }
+
+    @Test
+    void testToInstantWithDefaultNonNullIgnoresDefault() {
+        final Instant value = Instant.ofEpochMilli(1_000L);
+        final Instant defaultInstant = Instant.ofEpochMilli(9_999L);
+        assertSame(value, Instants.toInstant(value, defaultInstant));
+    }
+
+    @Test
+    void testToInstantWithDefaultNonNullReturnsSameInstance() {
+        final Instant now = Instant.now();
+        assertSame(now, Instants.toInstant(now, Instant.EPOCH));
+    }
+
+    @Test
+    void testToInstantWithDefaultNullAndEpochDefaultReturnsEpoch() {
+        assertSame(Instant.EPOCH, Instants.toInstant(null, Instant.EPOCH));
+    }
+
+    @Test
+    void testToInstantWithDefaultNullReturnsDefault() {
+        final Instant defaultInstant = Instant.ofEpochMilli(12345L);
+        assertSame(defaultInstant, Instants.toInstant(null, defaultInstant));
+    }
+
+    @Test
+    void testToInstantWithDefaultNullReturnsNullDefault() {
+        assertSame(null, Instants.toInstant(null, null));
+    }
+
     /**
      * Epoch instant (time zero): milliseconds since epoch should be positive 
and equal to
      * roughly the current time in millis (with a generous lower bound).

Reply via email to