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

exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 45ba85724cd NIFI-16157 Added millis to formatDurationToWords (#11496)
45ba85724cd is described below

commit 45ba85724cd21bbc0713890ebe76c2ba490a60ad
Author: David Young <[email protected]>
AuthorDate: Mon Aug 3 17:01:54 2026 -0400

    NIFI-16157 Added millis to formatDurationToWords (#11496)
    
    Signed-off-by: David Handermann <[email protected]>
---
 .../java/org/apache/nifi/util/FormatUtils.java     | 19 +++++--
 .../java/org/apache/nifi/util/TestFormatUtils.java | 63 ++++++++++++----------
 2 files changed, 48 insertions(+), 34 deletions(-)

diff --git 
a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java 
b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java
index b339c2bd8a8..02071526c4b 100644
--- 
a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java
+++ 
b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java
@@ -44,6 +44,9 @@ public class FormatUtils {
     // 'public static final' members defined for backward compatibility, since 
they were moved to TimeFormat.
     public static final String TIME_DURATION_REGEX = 
DurationFormat.TIME_DURATION_REGEX;
     public static final Pattern TIME_DURATION_PATTERN = 
DurationFormat.TIME_DURATION_PATTERN;
+
+    private static final int NANOS_PER_MILLI = 1_000_000;
+
     /**
      * Formats the specified count by adding commas.
      *
@@ -394,8 +397,9 @@ public class FormatUtils {
     }
 
     /**
-     * Format a Duration using words (days, hours, minutes, seconds, ns) where 
all lower units are
-     *   included once a non-zero unit is found. Unit plurality is preserved.
+     * Format a Duration using indicators (d, h, m, s, ms, ns) where lower 
units down to seconds are
+     *   included once a non-zero unit is found.
+     * Sub-seconds are included if non-zero.
      * Maximum resolution is in terms of days.
      *
      * @param source duration to convert to words
@@ -406,7 +410,8 @@ public class FormatUtils {
         final long hours = source.toHoursPart();
         final long minutes = source.toMinutesPart();
         final int seconds = source.toSecondsPart();
-        final int nanos = source.toNanosPart();
+        final int millis = source.toMillisPart();
+        final int nanosLeft = source.toNanosPart() % NANOS_PER_MILLI;
 
         final List<String> parts = new ArrayList<>();
 
@@ -422,8 +427,12 @@ public class FormatUtils {
         if (seconds > 0 || !parts.isEmpty()) {
             parts.add(seconds + "s");
         }
-        if (nanos > 0 || !parts.isEmpty()) {
-            parts.add(nanos + "ns");
+        // ns includes ms, but omit ns if zero
+        if (millis > 0 || nanosLeft > 0) {
+            parts.add(millis + "ms");
+        }
+        if (nanosLeft > 0) {
+            parts.add(nanosLeft + "ns");
         }
 
         return String.join(" ", parts);
diff --git 
a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java
 
b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java
index 678729ba1d4..d4c8d01aafa 100644
--- 
a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java
+++ 
b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java
@@ -178,6 +178,24 @@ public class TestFormatUtils {
         assertEquals(expected, 
FormatUtils.formatHoursMinutesSeconds(sourceDuration, sourceUnit));
     }
 
+    private static Stream<Arguments> getFormatTime() {
+        return Stream.of(Arguments.of(0L, TimeUnit.DAYS, "00:00:00.000"),
+                Arguments.of(1L, TimeUnit.HOURS, "01:00:00.000"),
+                Arguments.of(2L, TimeUnit.HOURS, "02:00:00.000"),
+                Arguments.of(1L, TimeUnit.MINUTES, "00:01:00.000"),
+                Arguments.of(10L, TimeUnit.SECONDS, "00:00:10.000"),
+                Arguments.of(777L, TimeUnit.MILLISECONDS, "00:00:00.777"),
+                Arguments.of(7777, TimeUnit.MILLISECONDS, "00:00:07.777"),
+                Arguments.of(TimeUnit.MILLISECONDS.convert(20, TimeUnit.HOURS)
+                        + TimeUnit.MILLISECONDS.convert(11, TimeUnit.MINUTES)
+                        + TimeUnit.MILLISECONDS.convert(36, TimeUnit.SECONDS)
+                        + TimeUnit.MILLISECONDS.convert(897, 
TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, "20:11:36.897"),
+                Arguments.of(TimeUnit.MILLISECONDS.convert(999, TimeUnit.HOURS)
+                        + TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES)
+                        + TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS)
+                        + TimeUnit.MILLISECONDS.convert(1001, 
TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, "1000:01:01.001"));
+    }
+
     @ParameterizedTest
     @MethodSource("getRelativeTimeArguments")
     public void testFormatRelativeTime(final long differenceMillis, final 
String expected) {
@@ -233,24 +251,6 @@ public class TestFormatUtils {
         );
     }
 
-    private static Stream<Arguments> getFormatTime() {
-        return Stream.of(Arguments.of(0L, TimeUnit.DAYS, "00:00:00.000"),
-            Arguments.of(1L, TimeUnit.HOURS, "01:00:00.000"),
-            Arguments.of(2L, TimeUnit.HOURS, "02:00:00.000"),
-            Arguments.of(1L, TimeUnit.MINUTES, "00:01:00.000"),
-            Arguments.of(10L, TimeUnit.SECONDS, "00:00:10.000"),
-            Arguments.of(777L, TimeUnit.MILLISECONDS, "00:00:00.777"),
-            Arguments.of(7777, TimeUnit.MILLISECONDS, "00:00:07.777"),
-            Arguments.of(TimeUnit.MILLISECONDS.convert(20, TimeUnit.HOURS)
-                         + TimeUnit.MILLISECONDS.convert(11, TimeUnit.MINUTES)
-                         + TimeUnit.MILLISECONDS.convert(36, TimeUnit.SECONDS)
-                         + TimeUnit.MILLISECONDS.convert(897, 
TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, "20:11:36.897"),
-            Arguments.of(TimeUnit.MILLISECONDS.convert(999, TimeUnit.HOURS)
-                         + TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES)
-                         + TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS)
-                         + TimeUnit.MILLISECONDS.convert(1001, 
TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, "1000:01:01.001"));
-    }
-
     @ParameterizedTest
     @MethodSource("getDurationValues")
     public void testFormatDurationToWords(Duration duration, String expected) {
@@ -259,17 +259,22 @@ public class TestFormatUtils {
 
     private static Stream<Arguments> getDurationValues() {
         return Stream.of(
-                Arguments.of(Duration.parse("PT0.000000001S"), "1ns"),
-                Arguments.of(Duration.parse("PT0.000000002S"), "2ns"),
-                Arguments.of(Duration.parse("PT1S"), "1s 0ns"),
-                Arguments.of(Duration.parse("PT2S"), "2s 0ns"),
-                Arguments.of(Duration.parse("PT1M"), "1m 0s 0ns"),
-                Arguments.of(Duration.parse("PT2M"), "2m 0s 0ns"),
-                Arguments.of(Duration.parse("PT1H"), "1h 0m 0s 0ns"),
-                Arguments.of(Duration.parse("PT2H"), "2h 0m 0s 0ns"),
-                Arguments.of(Duration.parse("P1D"), "1d 0h 0m 0s 0ns"),
-                Arguments.of(Duration.parse("P35D"), "35d 0h 0m 0s 0ns"),
-                Arguments.of(Duration.parse("P366D"), "366d 0h 0m 0s 0ns")
+                Arguments.of(Duration.parse("PT0.000000001S"), "0ms 1ns"),
+                Arguments.of(Duration.parse("PT0.001000001S"), "1ms 1ns"),
+                Arguments.of(Duration.parse("PT0.000000002S"), "0ms 2ns"),
+                Arguments.of(Duration.parse("PT1S"), "1s"),
+                Arguments.of(Duration.parse("PT1.001S"), "1s 1ms"),
+                Arguments.of(Duration.parse("PT1.000000001S"), "1s 0ms 1ns"),
+                Arguments.of(Duration.parse("PT1.001000001S"), "1s 1ms 1ns"),
+                Arguments.of(Duration.parse("PT2S"), "2s"),
+                Arguments.of(Duration.parse("PT1M"), "1m 0s"),
+                Arguments.of(Duration.parse("PT2M"), "2m 0s"),
+                Arguments.of(Duration.parse("PT1H"), "1h 0m 0s"),
+                Arguments.of(Duration.parse("PT2H"), "2h 0m 0s"),
+                Arguments.of(Duration.parse("P1D"), "1d 0h 0m 0s"),
+                Arguments.of(Duration.parse("PT25H"), "1d 1h 0m 0s"),
+                Arguments.of(Duration.parse("P35D"), "35d 0h 0m 0s"),
+                Arguments.of(Duration.parse("P366D"), "366d 0h 0m 0s")
         );
     }
 }

Reply via email to