Como posso “imprimir bem” uma Duração em Java?

Alguém sabe de uma biblioteca Java que pode imprimir um número em milissegundos da mesma forma que o C # faz?

Por exemplo, 123456 ms como um longo seria impresso como 4d1h3m5s.

Joda Time tem uma boa maneira de fazer isso usando um PeriodFormatterBuilder .

Win Rápido: PeriodFormat.getDefault().print(duration.toPeriod());

por exemplo

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

Eu criei uma solução simples, usando Duration.toString() Java 8 e um pouco de regex:

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

O resultado será parecido com:

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

Se você não quer espaços entre, apenas remova replaceAll .

JodaTime tem uma class Period que pode representar tais quantidades, e pode ser renderizada (via IsoPeriodFormat ) no formato PT4D1H3M5S , por exemplo, PT4D1H3M5S , por exemplo

 Period period = new Period(millis); String formatted = ISOPeriodFormat.standard().print(period); 

Se esse formato não for o que você deseja, o PeriodFormatterBuilder permite montar layouts arbitrários, incluindo os 4d1h3m5s estilo C #.

Com o Java 8, você também pode usar o toString() de java.time.Duration para formatá-lo sem bibliotecas externas usando a representação baseada em segundos do ISO 8601 , como PT8H6M12.345S.

O commons-lang do Apache fornece uma class útil para fazer isso bem como DurationFormatUtils

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

Veja como você pode fazer isso usando o código JDK puro:

 import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; long diffTime = 215081000L; Duration duration = DatatypeFactory.newInstance().newDuration(diffTime); System.out.printf("%02d:%02d:%02d", duration.getDays() * 24 + duration.getHours(), duration.getMinutes(), duration.getSeconds()); 

Eu percebo que isso pode não se encheckboxr exatamente no seu caso de uso, mas o PrettyTime pode ser útil aqui.

 PrettyTime p = new PrettyTime(); System.out.println(p.format(new Date())); //prints: “right now” System.out.println(p.format(new Date(1000*60*10))); //prints: “10 minutes from now” 

Uma alternativa para a abordagem construtora do Joda-Time seria uma solução baseada em padrões . Isso é oferecido pela minha biblioteca Time4J . Exemplo usando a class Duration.Formatter (adicionou alguns espaços para maior legibilidade – remover os espaços produzirá o estilo desejado em C #):

 IsoUnit unit = ClockUnit.MILLIS; Duration dur = Duration.of(123456, unit).with(Duration.STD_PERIOD); String s = Duration.Formatter.ofPattern("D'd' h'h' m'm' s.fff's'").format(dur); System.out.println(s); // output: 0d 0h 2m 3.456s 

Outra maneira é usar a class net.time4j.PrettyTime (que também é boa para saída localizada e tempos relativos de impressão):

 s = PrettyTime.of(Locale.ENGLISH).print(dur, TextWidth.NARROW); System.out.println(s); // output: 2m 3s 456ms 

Java 9

 Duration d1 = Duration.ofDays(0); d1 = d1.plusHours(47); d1 = d1.plusMinutes(124); d1 = d1.plusSeconds(124); System.out.println(String.format("%sd %sh %sm %ss", d1.toDaysPart(), d1.toHoursPart(), d1.toMinutesPart(), d1.toSecondsPart())); 

2 d 1h 6m 4s

Uma versão do Java 8 com base na resposta do user678573 :

  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())); } 

… já que não há PeriodFormatter no Java 8 e nenhum método como getHours, getMinutes, …

Eu ficaria feliz em ver uma versão melhor para o Java 8.