Para sua informação, o formato que você parece estar descrevendo é Durationdefinido no padrão sensato, ISO 8601 : PnYnMnDTnHnMnSonde Psignifica "Ponto" e marca o início, Tsepara 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.
Basil Bourque
1
Se tudo mais falhar, é muito simples fazer você mesmo. Basta usar aplicações sucessivas de %e /para dividir o número em partes. Quase mais fácil do que algumas das respostas propostas.
Hot Licks de
@HotLicks Deixe isso para métodos de biblioteca para um código muito mais limpo e claro do que usar /e %.
Ole VV
Sim, nos 8 anos que se passaram desde que fiz esta pergunta (!) Mudei para o tempo joda, que se adapta muito bem ao meu caso de uso
phatmanace
@phatmanace O projeto Joda-Time está agora em modo de manutenção e aconselha a migração para as classes java.time construídas no Java 8 e posterior.
Parece com uma resposta abaixo que uma instância de Period pode ser criada diretamente, sem primeiro criar uma instância de Duration e depois convertê-la em Period. Por exemplo, período do período = novo período (milis); String formatada = formatter.print (ponto);
Basil Vandegriend
7
Cuidado com essa conversão "duration.toPeriod ()". Se a duração for muito grande, a parte do dia em diante permanecerá como 0. A parte das horas continuará crescendo. Você obterá 25h10m23s, mas nunca obterá o "d". A razão é que não existe uma maneira totalmente correta de converter horas em dias nos métodos estritos de Joda. Na maioria dos casos, se você está comparando dois instantes e quer imprimi-los, você pode fazer um novo Período (t1, t2) em vez de um novo Período (t1, t2) .toPeriod ().
Boon,
@Boon você sabe como converter a duração em período em relação aos dias? Eu uso a duração a partir da qual posso substituir o segundo no meu cronômetro. Configuração do evento PeriodType.daysTime()ou .standard()não ajudou
murt
4
@murt Se você realmente deseja e pode aceitar a definição padrão de um dia, você pode "formatter.print (duration.toPeriod (). normalizedStandard ())" no código acima. Diverta-se!
Boon
74
Criei uma solução simples, usando Java 8 Duration.toString()e um pouco de regex:
Você nunca deve confiar na saída de toStrong () porque isso pode mudar nas versões futuras.
Weltraumschaf
14
@Weltraumschaf não é provável que mude, já que está especificado no javadoc
aditsu quit porque SE é EVIL
9
@Weltraumschaf É improvável que mude, pois a saída de Duration::toStringé formatada de acordo com o padrão ISO 8601 bem definido e usado .
Basil Bourque
1
Se você não quiser frações, adicione .replaceAll("\\.\\d+", "")antes da chamada para toLowerCase().
zb226
1
@Weltraumschaf Seu ponto é geralmente correto e eu não confiaria na saída toString () da maioria das classes. Mas, neste caso muito específico, a definição do método afirma que sua saída segue o padrão ISO-8601, como você pode ver no Javadoc do método . Portanto, não é um detalhe de implementação como na maioria das classes, portanto, não é algo que eu esperaria que uma linguagem tão madura como Java mudasse assim,
lucasls
13
Apache commons-lang oferece uma classe útil para fazer isso também. DurationFormatUtils
JodaTime tem uma Periodclasse que pode representar tais quantidades, e pode ser renderizada (via IsoPeriodFormat) no formato ISO8601 , por exemplo PT4D1H3M5S, por exemplo
Period period =newPeriod(millis);String formatted =ISOPeriodFormat.standard().print(period);
Se esse formato não for o que você deseja, então PeriodFormatterBuilderpermite que você monte layouts arbitrários, incluindo seu estilo C # 4d1h3m5s.
O projeto ThreeTen-Extra , que é mantido por Stephen Colebourne, o autor de JSR 310, java.time e Joda-Time , tem uma AmountFormatsclasse 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()));
Uau, bom saber, eu não vi esse recurso. No entanto, tem uma grande falha: falta a vírgula Oxford .
Basil Bourque
4
@BasilBourque A vírgula Oxford é típica dos Estados Unidos, mas, curiosamente, não do Reino Unido. Minha lib Time4J (que tem uma internacionalização muito melhor) suporta essa distinção na classe net.time4j.PrettyTime e também permite o controle sobre a saída compacta, se desejado.
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 componentsDuration.of(123456, unit).with(Duration.STD_PERIOD);Duration.Formatter<IsoUnit> f =// create formatter/parser with optional millisDuration.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):
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):
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).
este PrettyTime é muito melhor do que o da outra resposta! pena que não achei isso primeiro.
ycomp
Não sei por que agora existem dois votos negativos para essa solução que funciona bem, então decidi estender a resposta, dando mais exemplos também sobre análise (o oposto de formatação) e para destacar a expectativa errada do OP.
@erickdeoliveiraleal Obrigado por apontar isso. Acho que estava escrevendo originalmente o código para groovy, então pode ter funcionado nessa linguagem. Eu corrigi para java agora.
Torsten
3
Sei que isso pode não se adequar exatamente ao seu caso de uso, mas PrettyTime pode ser útil aqui.
PrettyTime p =newPrettyTime();System.out.println(p.format(newDate()));//prints: “right now”System.out.println(p.format(newDate(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.%
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
fonte
PeriodType.daysTime()
ou.standard()
não ajudouCriei uma solução simples, usando Java 8
Duration.toString()
e um pouco de regex:O resultado será semelhante a:
Se você não quiser espaços entre, apenas remova
replaceAll
.fonte
Duration::toString
é formatada de acordo com o padrão ISO 8601 bem definido e usado ..replaceAll("\\.\\d+", "")
antes da chamada paratoLowerCase()
.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. ISO8601fonte
JodaTime tem uma
Period
classe que pode representar tais quantidades, e pode ser renderizada (viaIsoPeriodFormat
) no formato ISO8601 , por exemploPT4D1H3M5S
, por exemploSe esse formato não for o que você deseja, então
PeriodFormatterBuilder
permite que você monte layouts arbitrários, incluindo seu estilo C #4d1h3m5s
.fonte
new Period(millis).toString()
usa oISOPeriodFormat.standard()
por padrão.Com o Java 8, você também pode usar o
toString()
método dejava.time.Duration
para formatá-lo sem bibliotecas externas usando a representação baseada em segundos ISO 8601 , como PT8H6M12.345S.fonte
Veja como você pode fazer isso usando código JDK puro:
fonte
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.1 minute, 9 seconds and 86 milliseconds
fonte
Java 9+
2 d 1h 6m 4s
fonte
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):
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):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)
: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.):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).
fonte
Uma versão Java 8 baseada na resposta do usuário 678573 :
... 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.
fonte
Sei que isso pode não se adequar exatamente ao seu caso de uso, mas PrettyTime pode ser útil aqui.
fonte