W3docs

Java Duration

Represente intervalos de tempo (horas, minutos, segundos) em Java com a classe Duration.

Duration representa um intervalo de tempo medido em segundos e nanossegundos. "Duas horas." "Quinhentos milissegundos." "Quarenta e cinco minutos." Internamente são dois números — um long seconds e um int nanos — e toda operação sobre ele é aritmética inteira. Ele não conhece calendários, meses ou DST; se você informar 24 horas, significa exatamente 86.400 segundos, independentemente de esse período abranger uma transição de DST.

Este é o tipo correto para: medições de tempo, timeouts, tentativas com backoff exponencial, "aguardar no máximo X segundos," qualquer situação em que a resposta seja um intervalo de tempo real. O tipo complementar para durações em calendário ("um mês," "dois anos") é Period, abordado no próximo capítulo.

Criação

Três grupos de fábricas:

Duration.ofNanos(500_000_000);
Duration.ofMillis(500);
Duration.ofSeconds(45);
Duration.ofSeconds(60, 500_000_000);                         // with nanos
Duration.ofMinutes(2);
Duration.ofHours(1);
Duration.ofDays(7);                                           // exactly 7 * 24 hours

Duration.between(start, end);                                 // from two Temporals
Duration.parse("PT1H30M");                                    // ISO-8601: PT[hours]H[minutes]M[seconds]S

Duration.ofDays(n) é a fábrica que a maioria das pessoas usa e que a maioria entende de forma errada. Ela produz exatamente n * 24 * 3600 segundos. Em um dia de transição de DST, isso não é o mesmo que "o próximo dia no mesmo horário do relógio de parede." Para "um dia depois" em forma de calendário, LocalDate.plusDays(1) ou Period.ofDays(1) são as ferramentas corretas.

O formato de string é a duração ISO-8601: PT1H30M45S é uma hora, trinta minutos, quarenta e cinco segundos. O prefixo PT é obrigatório (P = Period, T = Time). Para componentes sub-segundo, a forma é PT0.5S ou PT0.000000001S. Duration cobre tudo abaixo do dia; períodos (ano, mês, dia) pertencem a Period.

Aritmética

d.plus(Duration.ofSeconds(15));
d.plusSeconds(60);
d.plusMinutes(5);
d.plusHours(2);
d.minus(Duration.ofMillis(100));
d.multipliedBy(3);
d.dividedBy(2);
d.negated();                                                  // -d
d.abs();

Cada método retorna um novo Duration (a imutabilidade que vem desde LocalDate em diante).

Os acessores de conversão:

d.toNanos();          // long
d.toMillis();         // long; throws if out of long range
d.toSeconds();        // since Java 9
d.toMinutes();
d.toHours();
d.toDays();           // assumes 24h days
d.getSeconds();       // raw seconds component
d.getNano();          // raw nanos component (0-999_999_999)

Os métodos toX() retornam um único long do total naquela unidade, truncando. Os métodos getX() retornam a decomposição bruta. São coisas diferentes; confundi-los é o erro mais comum com Duration.

Duration d = Duration.ofSeconds(125);
d.toMinutes();        // 2  (125 / 60)
d.getSeconds();       // 125 (raw)

Para formatação "X minutos Y segundos", use os dois:

long mins = d.toMinutes();
long secs = d.minusMinutes(mins).getSeconds();
System.out.printf("%d:%02d%n", mins, secs);                  // 2:05

Ou, desde o Java 9, os auxiliares de decomposição dedicados:

d.toHoursPart();       // hours within the duration (0-23-ish on positive durations)
d.toMinutesPart();     // minutes within the duration (0-59)
d.toSecondsPart();     // seconds within the duration (0-59)
d.toMillisPart();      // millis within the second

Esses são o que você precisa para "exibir 1h 23m 45s" sem precisar fazer o módulo manualmente.

Comparação

d1.isZero();           // d == 0
d1.isNegative();        // d < 0
d1.compareTo(d2);
d1.equals(d2);

Duration é Comparable<Duration>. A ordenação é com sinal — uma duração negativa é menor que zero, que é menor que uma duração positiva.

Distância entre dois Temporals

A fábrica Duration.between(start, end) é a que você usará com mais frequência:

Duration d = Duration.between(start, end);                    // works on Instant, LocalDateTime, ZonedDateTime, LocalTime

Ela aceita qualquer par de valores Temporal que suporte unidades baseadas em tempo. LocalDate (somente data) não suporta — Duration.between(date1, date2) lança DateTimeException porque uma data não tem componente de relógio. Para distância em calendário, use Period.between(date1, date2) ou ChronoUnit.DAYS.between(date1, date2).

A convenção de sinal: positivo se end for posterior a start, negativo caso contrário.

Adicionando a outros temporais

Duration é um TemporalAmount, portanto qualquer Temporal o aceita via plus/minus:

Instant later = Instant.now().plus(Duration.ofMinutes(30));
LocalDateTime then = LocalDateTime.now().plus(Duration.ofHours(8));

Adicionar um Duration a um LocalDate lança exceção — pelo mesmo motivo acima, sem componente de relógio. O compilador não captura isso; a chamada falha em tempo de execução. Se você quiser fazer isso, quase certamente quis dizer Period.

Um exemplo prático: medição de tempo, formatação, backoff

O programa abaixo mede o tempo decorrido de um pequeno trecho de trabalho, exibe-o em formato legível por humanos usando os auxiliares toXxxPart, computa um cronograma de backoff exponencial e demonstra o limite entre Duration e Period, mostrando tanto Duration.between em Instants quanto Period.between em LocalDates para o mesmo intervalo de tempo conceitual.

java— editable, runs on the server

O que observar na execução:

  • O bloco Thread.sleep(125) foi medido como PT0.125-something-S — o estouro real do sleep é variabilidade da máquina real. Duration.between(t0, t1) foi a chamada correta: dois Instants, sem zona necessária, resposta exata com a resolução do relógio do sistema.
  • Os auxiliares toXxxPart() forneceram inteiros limpos para "a parte das horas," "a parte dos minutos," "a parte dos segundos," "a parte dos milissegundos." Sem eles, você teria que fazer aritmética modular total / 3600 e (total % 3600) / 60 manualmente. Use-os sempre que precisar formatar uma duração para um humano.
  • O laço de backoff exponencial escalou a duração com multipliedBy(2) e imprimiu cada resultado. A forma de string ISO-8601 (PT2S, PT4S, PT8S, ...) é o que Duration.toString imprime; é concisa e inequívoca, ideal para logs.
  • O bloco "Jan 1 → Apr 1 em três formas" mostrou o limite entre Duration e Period. Period.between(start, end) retornou P3M — três meses de calendário. Duration.between nos instantes UTC equivalentes retornou uma contagem de tempo real (90 dias). Ambos estão corretos; eles respondem a perguntas diferentes. Escolha o que corresponde à intenção do seu código.
  • O bloco final tentou Duration.between(LocalDate, LocalDate) e obteve DateTimeException. O sistema de tipos sabe que uma data não tem componente de relógio, então se recusa a computar uma duração baseada em relógio. A correção é (1) anexar horas (startDate.atStartOfDay(zone)), ou (2) usar Period.between se uma contagem de calendário é o que você realmente quis dizer. A exceção é o design correto: respostas silenciosas a essa pergunta seriam enganosas.

O que vem a seguir

Duration é o comprimento em segundos e nanossegundos. O próximo capítulo, Java Period, é o comprimento em anos, meses e dias — o equivalente em calendário. Os dois nunca se misturam: Duration não conhece meses, Period não conhece horas, e qualquer código que lide com os dois recorre a um ou outro dependendo de se a resposta deve acompanhar o calendário ou o relógio de parede.

Prática

Prática
Você quer tentar novamente uma requisição HTTP após 'um dia,' ou seja, '24 horas a partir de agora, independentemente do DST.' Qual tipo e chamada fazem isso?
Você quer tentar novamente uma requisição HTTP após 'um dia,' ou seja, '24 horas a partir de agora, independentemente do DST.' Qual tipo e chamada fazem isso?
Was this page helpful?