Alguém conhece uma biblioteca Java que pode imprimir um número em milissegundos da mesma maneira que o C #?
Por exemplo, 123456 ms como um longo seria impresso como 4d1h3m5s.
Alguém conhece uma biblioteca Java que pode imprimir um número em milissegundos da mesma maneira que o C #?
Por exemplo, 123456 ms como um longo seria impresso como 4d1h3m5s.
%
e /
para dividir o número em partes. Quase mais fácil do que algumas das respostas propostas.
/
e %
.
Respostas:
Joda Time tem uma maneira muito boa de fazer isso usando um PeriodFormatterBuilder .
Vitória rápida: 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);
PeriodType.daysTime()
ou .standard()
não ajudou
Criei uma solução simples, usando Java 8 Duration.toString()
e um pouco de regex:
public static String humanReadableFormat(Duration duration) {
return duration.toString()
.substring(2)
.replaceAll("(\\d[HMS])(?!$)", "$1 ")
.toLowerCase();
}
O resultado será semelhante a:
- 5h
- 7h 15m
- 6h 50m 15s
- 2h 5s
- 0.1s
Se você não quiser espaços entre, apenas remova replaceAll
.
Duration::toString
é formatada de acordo com o padrão ISO 8601 bem definido e usado .
.replaceAll("\\.\\d+", "")
antes da chamada para toLowerCase()
.
Apache commons-lang oferece uma classe útil para fazer isso também. DurationFormatUtils
por exemplo,
DurationFormatUtils.formatDurationHMS( 15362 * 1000 ) )
=> 4: 16: 02.000 (H: m: s.millis)
DurationFormatUtils.formatDurationISO( 15362 * 1000 ) )
=> P0Y0M0DT4H16M2.000S, cf. ISO8601
JodaTime tem uma Period
classe que pode representar tais quantidades, e pode ser renderizada (via IsoPeriodFormat
) no formato ISO8601 , 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, então PeriodFormatterBuilder
permite que você monte layouts arbitrários, incluindo seu estilo C # 4d1h3m5s
.
new Period(millis).toString()
usa o ISOPeriodFormat.standard()
por padrão.
Com o Java 8, você também pode usar o toString()
método de java.time.Duration
para formatá-lo sem bibliotecas externas usando a representação baseada em segundos ISO 8601 , como PT8H6M12.345S.
Veja como você pode fazer isso usando 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());
org.threeten.extra.AmountFormats.wordBased
O projeto ThreeTen-Extra , que é mantido por Stephen Colebourne, o autor de JSR 310, java.time e Joda-Time , tem uma AmountFormats
classe que funciona com as classes de data e hora Java 8 padrão. É bastante prolixo, porém, sem opção para uma saída mais compacta.
Duration d = Duration.ofMinutes(1).plusSeconds(9).plusMillis(86);
System.out.println(AmountFormats.wordBased(d, Locale.getDefault()));
1 minute, 9 seconds and 86 milliseconds
Java 9+
Duration d1 = Duration.ofDays(0);
d1 = d1.plusHours(47);
d1 = d1.plusMinutes(124);
d1 = d1.plusSeconds(124);
System.out.println(String.format("%s d %sh %sm %ss",
d1.toDaysPart(),
d1.toHoursPart(),
d1.toMinutesPart(),
d1.toSecondsPart()));
2 d 1h 6m 4s
Uma alternativa para a abordagem do construtor do Joda-Time seria uma solução baseada em padrões . Isso é oferecido pela minha biblioteca Time4J . Exemplo usando a classe Duration.Formatter (adicionado alguns espaços para mais legibilidade - remover os espaços resultará no estilo C # desejado):
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
Este formatador também pode imprimir durações de java.time
-API (no entanto, os recursos de normalização desse tipo são menos poderosos):
System.out.println(f.format(java.time.Duration.ofMillis(123456))); // output: 0d 0h 2m 3.456s
A expectativa do OP de que "123456 ms como um longo seria impresso como 4d1h3m5s" é calculada de uma maneira obviamente errada. Assumo a negligência como razão. O mesmo formatador de duração definido acima também pode ser usado como analisador. O código a seguir mostra que "4d1h3m5s" corresponde a 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
Outra maneira é usar a classe net.time4j.PrettyTime
(que também é boa para saída localizada e impressão de tempos relativos como "ontem", "próximo domingo", "4 dias atrás" 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
A largura do texto controla se as abreviações são usadas ou não. O formato da lista também pode ser controlado escolhendo o local apropriado. Por exemplo, o inglês padrão usa a vírgula Oxform, enquanto o Reino Unido não. A última versão v5.5 do Time4J suporta mais de 90 idiomas e usa traduções baseadas no repositório CLDR (um padrão da indústria).
Uma versão Java 8 baseada na resposta do usuário 678573 :
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 Java 8.
Sei que isso pode não se adequar exatamente ao seu caso de uso, mas 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”
Duration
definido no padrão sensato, ISO 8601 :PnYnMnDTnHnMnS
ondeP
significa "Ponto" e marca o início,T
separa a parte da data da parte do tempo e entre as ocorrências opcionais de um número com um único - abreviatura da letra. Por exemplo,PT4H30M
= quatro horas e meia.