src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java
changeset 59312 43eee1237934
parent 58863 c16ac7a2eba4
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Thu Nov 28 13:02:30 2019 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Thu Nov 28 18:30:18 2019 +0100
@@ -45,6 +45,7 @@
 import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -78,6 +79,17 @@
     private static Boolean SAVE_GENERATED;
 
 
+    private static final Duration MICRO_SECOND = Duration.ofNanos(1_000);
+    private static final Duration SECOND = Duration.ofSeconds(1);
+    private static final Duration MINUTE = Duration.ofMinutes(1);
+    private static final Duration HOUR = Duration.ofHours(1);
+    private static final Duration DAY = Duration.ofDays(1);
+    private static final int NANO_SIGNIFICANT_FIGURES = 9;
+    private static final int MILL_SIGNIFICANT_FIGURES = 3;
+    private static final int DISPLAY_NANO_DIGIT = 3;
+    private static final int BASE = 10;
+
+
     public static void checkAccessFlightRecorder() throws SecurityException {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
@@ -597,6 +609,90 @@
         return "hotspot-" + "pid-" + pid + idText + "-" + date + ".jfr";
     }
 
+    public static String formatDuration(Duration d) {
+        Duration roundedDuration = roundDuration(d);
+        if (roundedDuration.equals(Duration.ZERO)) {
+            return "0 s";
+        } else if(roundedDuration.isNegative()){
+            return "-" + formatPositiveDuration(roundedDuration.abs());
+        } else {
+            return formatPositiveDuration(roundedDuration);
+        }
+    }
+
+    private static String formatPositiveDuration(Duration d){
+        if (d.compareTo(MICRO_SECOND) < 0) {
+            // 0.000001 ms - 0.000999 ms
+            double outputMs = (double) d.toNanosPart() / 1_000_000;
+            return String.format("%.6f ms",  outputMs);
+        } else if (d.compareTo(SECOND) < 0) {
+            // 0.001 ms - 999 ms
+            int valueLength = countLength(d.toNanosPart());
+            int outputDigit = NANO_SIGNIFICANT_FIGURES - valueLength;
+            double outputMs = (double) d.toNanosPart() / 1_000_000;
+            return String.format("%." + outputDigit + "f ms",  outputMs);
+        } else if (d.compareTo(MINUTE) < 0) {
+            // 1.00 s - 59.9 s
+            int valueLength = countLength(d.toSecondsPart());
+            int outputDigit = MILL_SIGNIFICANT_FIGURES - valueLength;
+            double outputSecond = d.toSecondsPart() + (double) d.toMillisPart() / 1_000;
+            return String.format("%." + outputDigit + "f s",  outputSecond);
+        } else if (d.compareTo(HOUR) < 0) {
+            // 1 m 0 s - 59 m 59 s
+            return String.format("%d m %d s",  d.toMinutesPart(), d.toSecondsPart());
+        } else if (d.compareTo(DAY) < 0) {
+            // 1 h 0 m - 23 h 59 m
+            return String.format("%d h %d m",  d.toHoursPart(), d.toMinutesPart());
+        } else {
+            // 1 d 0 h -
+            return String.format("%d d %d h",  d.toDaysPart(), d.toHoursPart());
+        }
+    }
+
+    private static int countLength(long value){
+        return (int) Math.log10(value) + 1;
+    }
+
+    private static Duration roundDuration(Duration d) {
+        if (d.equals(Duration.ZERO)) {
+            return d;
+        } else if(d.isNegative()){
+            Duration roundedPositiveDuration = roundPositiveDuration(d.abs());
+            return roundedPositiveDuration.negated();
+        } else {
+            return roundPositiveDuration(d);
+        }
+    }
+
+    private static Duration roundPositiveDuration(Duration d){
+        if (d.compareTo(MICRO_SECOND) < 0) {
+            // No round
+            return d;
+        } else if (d.compareTo(SECOND) < 0) {
+            // Round significant figures to three digits
+            int valueLength = countLength(d.toNanosPart());
+            int roundValue = (int) Math.pow(BASE, valueLength - DISPLAY_NANO_DIGIT);
+            long roundedNanos = Math.round((double) d.toNanosPart() / roundValue) * roundValue;
+            return d.truncatedTo(ChronoUnit.SECONDS).plusNanos(roundedNanos);
+        } else if (d.compareTo(MINUTE) < 0) {
+            // Round significant figures to three digits
+            int valueLength = countLength(d.toSecondsPart());
+            int roundValue = (int) Math.pow(BASE, valueLength);
+            long roundedMills = Math.round((double) d.toMillisPart() / roundValue) * roundValue;
+            return d.truncatedTo(ChronoUnit.SECONDS).plusMillis(roundedMills);
+        } else if (d.compareTo(HOUR) < 0) {
+            // Round for more than 500 ms or less
+            return d.plusMillis(SECOND.dividedBy(2).toMillisPart()).truncatedTo(ChronoUnit.SECONDS);
+        } else if (d.compareTo(DAY) < 0) {
+            // Round for more than 30 seconds or less
+            return d.plusSeconds(MINUTE.dividedBy(2).toSecondsPart()).truncatedTo(ChronoUnit.MINUTES);
+        } else {
+            // Round for more than 30 minutes or less
+            return d.plusMinutes(HOUR.dividedBy(2).toMinutesPart()).truncatedTo(ChronoUnit.HOURS);
+        }
+    }
+
+
     public static void takeNap(long millis) {
         try {
             Thread.sleep(millis);