How can I “pretty print” a Duration in Java?

前端 未结 11 684
盖世英雄少女心
盖世英雄少女心 2020-11-28 07:45

Does anyone know of a Java library that can pretty print a number in milliseconds in the same way that C# does?

E.g., 123456 ms as a long would be printed as 4d1h3m5

相关标签:
11条回答
  • 2020-11-28 08:30

    I've built a simple solution, using Java 8's Duration.toString() and a bit of regex:

    public static String humanReadableFormat(Duration duration) {
        return duration.toString()
                .substring(2)
                .replaceAll("(\\d[HMS])(?!$)", "$1 ")
                .toLowerCase();
    }
    

    The result will look like:

    - 5h
    - 7h 15m
    - 6h 50m 15s
    - 2h 5s
    - 0.1s
    

    If you don't want spaces between, just remove replaceAll.

    0 讨论(0)
  • 2020-11-28 08:30

    Apache commons-lang provides a useful class to get this done as well DurationFormatUtils

    e.g. DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) ) => 4:16:02.000 (H:m:s.millis) DurationFormatUtils.formatDurationISO( 15362 * 1000 ) ) => P0Y0M0DT4H16M2.000S, cf. ISO8601

    0 讨论(0)
  • 2020-11-28 08:32

    Joda Time has a pretty good way to do this using a PeriodFormatterBuilder.

    Quick Win: PeriodFormat.getDefault().print(duration.toPeriod());

    e.g.

    //import org.joda.time.format.PeriodFormatter;
    //import org.joda.time.format.PeriodFormatterBuilder;
    //import org.joda.time.Duration;
    
    Duration duration = new Duration(123456); // in milliseconds
    PeriodFormatter formatter = new PeriodFormatterBuilder()
         .appendDays()
         .appendSuffix("d")
         .appendHours()
         .appendSuffix("h")
         .appendMinutes()
         .appendSuffix("m")
         .appendSeconds()
         .appendSuffix("s")
         .toFormatter();
    String formatted = formatter.print(duration.toPeriod());
    System.out.println(formatted);
    
    0 讨论(0)
  • 2020-11-28 08:33

    An alternative to the builder-approach of Joda-Time would be a pattern-based solution. This is offered by my library Time4J. Example using the class Duration.Formatter (added some spaces for more readability - removing the spaces will yield the wished C#-style):

    IsoUnit unit = ClockUnit.MILLIS;
    Duration<IsoUnit> dur = // normalized duration with multiple components
      Duration.of(123456, unit).with(Duration.STD_PERIOD);
    Duration.Formatter<IsoUnit> f = // create formatter/parser with optional millis
      Duration.Formatter.ofPattern("D'd' h'h' m'm' s[.fff]'s'");
    
    System.out.println(f.format(dur)); // output: 0d 0h 2m 3.456s
    

    This formatter can also print durations of java.time-API (however, the normalization features of that type are less powerful):

    System.out.println(f.format(java.time.Duration.ofMillis(123456))); // output: 0d 0h 2m 3.456s
    

    The expectation of the OP that "123456 ms as a long would be printed as 4d1h3m5s" is calculated in an obviously wrong way. I assume sloppiness as reason. The same duration formatter defined above can also be used as parser. The following code shows that "4d1h3m5s" rather corresponds to 349385000 = 1000 * (4 * 86400 + 1 * 3600 + 3 * 60 + 5):

    System.out.println(
      f.parse("4d 1h 3m 5s")
       .toClockPeriodWithDaysAs24Hours()
       .with(unit.only())
       .getPartialAmount(unit)); // 349385000
    

    Another way is using the class net.time4j.PrettyTime (which is also good for localized output and printing relative times like "yesterday", "next Sunday", "4 days ago" etc.):

    String s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW);
    System.out.println(s); // output: 2m 3s 456ms
    
    s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.WIDE);
    System.out.println(s); // output: 2 minutes, 3 seconds, and 456 milliseconds
    
    s = PrettyTime.of(Locale.UK).print(dur, TextWidth.WIDE);
    System.out.println(s); // output: 2 minutes, 3 seconds and 456 milliseconds
    

    The text width controls if abbreviations are used or not. The list format can be controlled, too, by choosing the appropriate locale. For example, standard English uses the Oxform comma, while UK does not. The latest version v5.5 of Time4J supports more than 90 languages and uses translations based on the CLDR-repository (an industry standard).

    0 讨论(0)
  • 2020-11-28 08:36

    A Java 8 version based on user678573's answer:

    private static String humanReadableFormat(Duration duration) {
        return String.format("%s days and %sh %sm %ss", duration.toDays(),
                duration.toHours() - TimeUnit.DAYS.toHours(duration.toDays()),
                duration.toMinutes() - TimeUnit.HOURS.toMinutes(duration.toHours()),
                duration.getSeconds() - TimeUnit.MINUTES.toSeconds(duration.toMinutes()));
    }
    

    ... since there is no PeriodFormatter in Java 8 and no methods like getHours, getMinutes, ...

    I'd be happy to see a better version for Java 8.

    0 讨论(0)
提交回复
热议问题