W3docs

Java Duration

Rappresenta intervalli di tempo (ore, minuti, secondi) in Java con la classe Duration.

Duration rappresenta una lunghezza di tempo misurata in secondi e nanosecondi. "Due ore." "Cinquecento millisecondi." "Quarantacinque minuti." Internamente è composta da due numeri — un long seconds e un int nanos — e ogni operazione su di essa è aritmetica intera. Non conosce calendari, mesi o DST; se le dici 24 ore, significa esattamente 86.400 secondi, indipendentemente dal fatto che quelle 24 ore attraversino una transizione DST.

Questo è il tipo giusto per: misurazioni di tempo, timeout, retry con backoff esponenziale, "attendi al massimo X secondi," qualsiasi cosa in cui la risposta è un intervallo di tempo reale. Il tipo complementare per lunghezze calendario ("un mese," "due anni") è Period, trattato nel prossimo capitolo.

Creazione

Tre gruppi di factory:

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) è la factory più usata e quella più spesso fraintesa. Produce esattamente n * 24 * 3600 secondi. In un giorno di transizione DST, questo non equivale a "il giorno successivo alla stessa ora del clock." Per un "giorno dopo" con forma calendario, LocalDate.plusDays(1) o Period.ofDays(1) sono gli strumenti giusti.

Il formato stringa è la durata ISO-8601: PT1H30M45S significa un'ora, trenta minuti, quarantacinque secondi. Il prefisso PT è obbligatorio (P = Period, T = Time). Per componenti inferiori al secondo, la forma è PT0.5S o PT0.000000001S. Duration copre tutto ciò che è inferiore al giorno; i periodi (anno, mese, giorno) appartengono a Period.

Aritmetica

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

Ogni metodo restituisce un nuovo Duration (il principio di immutabilità introdotto da LocalDate in poi).

Gli accessor di conversione:

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)

I metodi toX() restituiscono un singolo long del totale in quella unità, troncando. I metodi getX() restituiscono la decomposizione grezza. Sono cose diverse; confonderli è il bug più comune con Duration.

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

Per la formattazione "X minuti Y secondi," usa entrambi:

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

Oppure, da Java 9, gli appositi helper di decomposizione:

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

Questi sono ciò che serve per "visualizzare 1h 23m 45s" senza dover fare il modulo a mano.

Confronto

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

Duration è Comparable<Duration>. L'ordinamento è con segno — una durata negativa è minore di zero, che è minore di una durata positiva.

Distanza tra due Temporal

La factory Duration.between(start, end) è quella che userai di più:

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

Accetta qualsiasi coppia di valori Temporal che supportano unità basate sul tempo. LocalDate (solo data) non lo fa — Duration.between(date1, date2) lancia DateTimeException perché una data non ha una componente di clock. Per la distanza calendario, usa Period.between(date1, date2) o ChronoUnit.DAYS.between(date1, date2).

La convenzione sul segno: positivo se end è dopo start, negativo altrimenti.

Aggiunta ad altri temporali

Duration è un TemporalAmount, quindi qualsiasi Temporal lo accetta tramite plus/minus:

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

Aggiungere una Duration a una LocalDate lancia un'eccezione — stessa ragione di cui sopra, nessuna componente di clock. Il compilatore non rileva questo errore; la chiamata fallisce a runtime. Se ti trovi a volerlo fare, quasi certamente intendevi Period.

Un esempio pratico: timing, formattazione, backoff

Il programma di seguito misura il tempo trascorso di un piccolo pezzo di lavoro, lo stampa in forma leggibile usando gli helper toXxxPart, calcola un piano di backoff esponenziale e dimostra il confine Duration vs Period mostrando sia Duration.between su Instant che Period.between su LocalDate per lo stesso intervallo di tempo concettuale.

java— editable, runs on the server

Cosa ricavare dall'esecuzione:

  • Il blocco Thread.sleep(125) è stato misurato come PT0.125-qualcosa-S — la variabilità effettiva dell'overshoot di sleep dipende dalla macchina reale. Duration.between(t0, t1) era la chiamata giusta: due Instant, nessuna zona necessaria, risposta esatta alla risoluzione del clock di sistema.
  • Gli helper toXxxPart() hanno fornito interi puliti per "la parte delle ore," "la parte dei minuti," "la parte dei secondi," "la parte dei millis." Senza di essi dovresti fare total / 3600 e (total % 3600) / 60 aritmetica modulare a mano. Usali ogni volta che hai bisogno di formattare una durata per un utente.
  • Il ciclo di backoff esponenziale ha scalato la durata con multipliedBy(2) e ha stampato ogni risultato. La forma stringa ISO-8601 (PT2S, PT4S, PT8S, ...) è ciò che stampa Duration.toString; è concisa e non ambigua, ideale per i log.
  • Il blocco "Jan 1 → Apr 1 in tre forme" ha mostrato il confine Duration vs Period. Period.between(start, end) ha restituito P3M — tre mesi calendario. Duration.between sugli istanti UTC equivalenti ha restituito un conteggio di tempo reale (90 giorni). Entrambi sono corretti; rispondono a domande diverse. Scegli quello il cui significato corrisponde all'intento del codice.
  • Il blocco finale ha provato Duration.between(LocalDate, LocalDate) e ha ottenuto DateTimeException. Il sistema dei tipi sa che una data non ha una componente di clock, quindi si rifiuta di calcolare una durata basata sul clock. La soluzione è: (1) allegare tempi (startDate.atStartOfDay(zone)), oppure (2) usare Period.between se è un conteggio calendario quello che intendi veramente. L'eccezione è il design corretto: risposte silenziose a quella domanda sarebbero fuorvianti.

Cosa viene dopo

Duration è la lunghezza in secondi e nanosecondi. Il prossimo capitolo, Java Period, è la lunghezza in anni, mesi e giorni — la controparte con forma calendario. I due non si mescolano mai: Duration non conosce i mesi, Period non conosce le ore, e qualsiasi codice che gestisce entrambi sceglie l'uno o l'altro a seconda che la risposta debba seguire il calendario o il clock reale.

Pratica

Pratica
Vuoi riprovare una richiesta HTTP dopo 'un giorno,' intendendo '24 ore da adesso indipendentemente dal DST.' Quale tipo e chiamata lo fanno?
Vuoi riprovare una richiesta HTTP dopo 'un giorno,' intendendo '24 ore da adesso indipendentemente dal DST.' Quale tipo e chiamata lo fanno?
Was this page helpful?