Duration — una classe immutabile del pacchetto java.time che rappresenta la durata tra due momenti nel tempo in secondi e nanosecondi. Duration misura quantità di tempo basate sul tempo — ore, minuti, secondi, millisecondi e nanosecondi. Secondo le specifiche di Oracle Java 17 (2024), a differenza di Period (che misura anni-mesi-giorni), Duration lavora con unità di tempo precise e non dipende dal calendario.
Punti chiave
Duration è una classe che modella la quantità di tempo in secondi e nanosecondi. Rappresenta una durata basata sul tempo, ovvero un numero fisico di secondi non legato a un calendario. Duration può essere pensata come “125 minuti” o “2 ore 5 minuti” — a differenza di Period, che direbbe “2 mesi”.
La rappresentazione interna di Duration consiste in due campi: long seconds (secondi) e int nanos (nanosecondi, da 0 a 999999999). Il valore può essere negativo — significa una durata “all’indietro” nel tempo. Il valore massimo è ±31557014167219200 secondi.
Secondo Baeldung (2024), Duration è una classe chiave per calcolare la durata delle operazioni, impostare timeout e misurare le prestazioni. Duration è immutabile e thread-safe, consentendone l’uso in ambienti multithread senza sincronizzazione.
La classe implementa le interfacce Comparable, TemporalAmount e TemporalUnit. TemporalAmount permette di utilizzare Duration nei metodi plus/minus delle classi LocalTime, LocalDateTime, Instant e ZonedDateTime.
La differenza principale è che Duration misura il numero esatto di secondi (basato sul tempo), mentre Period misura unità di calendario (basate sulla data): anni, mesi, giorni. Duration dice: “86400 secondi sono passati.” Period dice: “1 giorno è passato.” La differenza diventa evidente durante i cambi dell’ora legale — 1 giorno in Period è sempre 1 giorno di calendario, mentre 86400 secondi in Duration possono corrispondere a 23 o 25 ore durante il DST.
Duration viene utilizzata per misurare il tempo fisico: timeout di connessione, tempo di esecuzione delle query, intervalli tra due Instant. Period viene utilizzata per calcoli di calendario: età di una persona (Period.between(dateOfBirth, today)), durata di un contratto.
Duration lavora con secondi e nanosecondi, quindi può essere suddivisa in parti (ore, minuti). Period lavora con anni, mesi e giorni — unità di calendario indivisibili. Secondo Oracle Java Tutorial (2024), la scelta tra Duration e Period dipende dal tipo di attività: tempo preciso vs date di calendario.
Il metodo più comune è Duration.between(Temporal start, Temporal end). Temporal può essere Instant, LocalTime, LocalDateTime, ZonedDateTime — qualsiasi tipo che implementi Temporal. Il metodo restituisce una Duration che rappresenta la differenza start - end (può essere negativa).
Metodi factory statici: Duration.ofSeconds(long), ofMinutes(long), ofHours(long), ofDays(long), ofMillis(long), ofNanos(long). Esiste anche of(long amount, TemporalUnit unit) per unità arbitrarie — ChronoUnit.HOURS, ChronoUnit.MINUTES e altre.
Il metodo parse(CharSequence) accetta una stringa in formato ISO-8601: “PT1H30M” (1 ora 30 minuti), “PT45S” (45 secondi), “P2DT3H” (2 giorni 3 ore). La stringa inizia sempre con “PT” (Period of Time).
val betweenMoments = Duration.between(
Instant.parse("2026-07-21T10:00:00Z"),
Instant.parse("2026-07-21T14:30:00Z")
)
val fromMinutes = Duration.ofMinutes(90)
val fromHours = Duration.ofHours(2)
val parsed = Duration.parse("PT1H30M")
Duration supporta un set completo di operazioni aritmetiche. I metodi plus(Duration) e minus(Duration) aggiungono o sottraggono un’altra durata. I metodi plusDays(), plusHours(), plusMinutes(), plusSeconds(), plusMillis(), plusNanos() — per aggiungere unità specifiche.
Per moltiplicazione e divisione, usa multipliedBy(long) e dividedBy(long). Duration.multipliedBy(2) raddoppia la durata. Duration.dividedBy(3) divide in tre parti con arrotondamento per difetto. Il metodo negated() inverte il segno — il positivo diventa negativo e viceversa.
Il metodo abs() restituisce una Duration con valore assoluto (positivo). isNegative() e isZero() sono controlli. toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos() convertono nelle unità corrispondenti.
val oneHour = Duration.ofHours(1)
val twoHours = oneHour.plus(Duration.ofMinutes(60))
val halfHour = oneHour.dividedBy(2)
val minutes = twoHours.toMinutes()
val absDuration = (Duration.ofHours(-1)).abs()
Duration implementa l’interfaccia Comparable, consentendo di confrontare le durate naturalmente. Il metodo compareTo() restituisce un numero negativo, zero o positivo. isNegative() e isZero() sono controlli rapidi. Per un confronto esplicito, usa equals() — due Duration sono uguali se i loro secondi e nanosecondi coincidono.
Poiché Duration può essere negativa, i confronti “maggiore di” o “minore di” funzionano considerando il segno. -5 minuti è minore di 2 minuti. Il metodo abs() è utile per confrontare lunghezze “assolute” indipendentemente dalla direzione.
In Kotlin, Duration supporta gli operatori di confronto tramite l’overloading degli operatori: a < b, a > b, a <= b. Plus e minus sono disponibili anche come operatori: a + b, a - b.
val short = Duration.ofMinutes(5)
val long = Duration.ofMinutes(10)
if (short < long) {
Log.d("Duration", "5 min è meno di 10")
}
val negative = Duration.ofMinutes(-3)
Log.d("Duration", "Negativo: ${negative.isNegative()}")
Il primo esempio è la configurazione della sincronizzazione periodica con il server. Duration viene utilizzata per calcolare l’intervallo tra le sincronizzazioni e verificare se il limite di tempo senza aggiornamento è stato superato.
data class SyncConfig(
val interval: Duration = Duration.ofMinutes(15),
val retryDelay: Duration = Duration.ofSeconds(30)
)
fun calculateNextSync(
lastSync: Instant,
config: SyncConfig
): Duration {
val elapsed = Duration.between(lastSync, Instant.now())
return config.interval.minus(elapsed)
.coerceAtLeast(Duration.ZERO)
}
Il secondo esempio è la misurazione del tempo di esecuzione di un’operazione per la registrazione delle prestazioni.
fun measureExecution(
tag: String,
block: () -> Unit
) {
val start = Instant.now()
block()
val duration = Duration.between(start, Instant.now())
Log.d(tag, "Eseguito in ${duration.toMillis()} ms")
}
Il terzo esempio è il calcolo del tempo rimanente di un timer (ad esempio, il conto alla rovescia fino alla fine di una promozione).
class CountdownTimer(
private val expiresAt: Instant
) {
fun getRemainingTime(): Duration {
val remaining = Duration.between(
Instant.now(), expiresAt
)
return remaining.coerceAtLeast(Duration.ZERO)
}
fun isExpired(): Boolean = getRemainingTime() == Duration.ZERO
}
Il metodo toString() restituisce Duration in formato ISO-8601: “PT1H30M” (1 ora 30 minuti), “PT45.5S” (45.5 secondi). Questo formato è comodo per lo scambio tra macchine ma non per la visualizzazione all’utente.
Per un formato leggibile dall’uomo, usa toDays(), toHours(), toMinutes(), toSeconds() seguiti dalla costruzione manuale della stringa. Ad esempio: “${days} g ${hours} h ${minutes} min”. Nota che toHours() restituisce il numero totale di ore, non le ore all’interno del giorno.
Per scomporre Duration in componenti, usa la formula: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. Secondo Apache Commons Lang (2024), la libreria DurationFormatUtils fornisce capacità di formattazione aggiuntive.
fun formatDuration(duration: Duration): String {
val hours = duration.toHours()
val minutes = duration.toMinutes() % 60
val seconds = duration.seconds % 60
return buildString {
if (hours > 0) append("${hours} h ")
if (minutes > 0) append("${minutes} min ")
append("${seconds} sec")
}
}
Il primo errore è confondere Duration e Period quando si lavora con le date. Duration misura secondi, quindi Duration.ofDays(1) è sempre 24 ore (86400 secondi), indipendentemente dai cambi dell’ora legale. Se hai bisogno di un giorno di calendario, usa Period.ofDays(1).
Il secondo errore è la perdita di nanosecondi durante la conversione. Duration può memorizzare nanosecondi, ma toMillis() e toSeconds() li scartano. Per calcoli precisi, usa toNanos() o lavora direttamente con Duration senza convertire in primitivi.
Il terzo errore è ignorare Duration negative. Duration.between(start, end) restituisce start - end. Se start è dopo end, Duration sarà negativa. Il metodo abs() aiuta a ottenere il valore assoluto e isNegative() verifica l’ordine degli argomenti.
Il quarto errore è una formattazione errata di Duration per l’interfaccia utente. Duration.toString() restituisce ISO-8601, che non è leggibile. Formatta sempre Duration manualmente per la visualizzazione all’utente usando toHours(), toMinutes() e toSeconds() con il resto corretto della divisione.
Domande frequenti
Sì, Duration può essere negativa. Duration.between(start, end) restituisce start - end. Se start è dopo end, Duration sarà negativa. Usa abs() per ottenere il valore assoluto o isNegative() per verificare.
Usa il metodo plus(Duration) o l’operatore + in Kotlin: duration1 + duration2. Il risultato è una nuova Duration. Il metodo minus(Duration) sottrae una durata da un’altra. Tutte le operazioni sono immutabili e restituiscono un nuovo oggetto.
Duration.ofDays(1) è sempre 24 ore (86400 secondi). Period.ofDays(1) è 1 giorno di calendario, che durante il DST può essere 23 o 25 ore. Per calcoli di tempo precisi, usa Duration; per calcoli di calendario, usa Period.
Usa il metodo toMillis(). Restituisce un long — il numero di millisecondi nella Duration. Per i nanosecondi, usa toNanos(). Attenzione: toNanos() può far overfloware long per valori > 292 anni. Per Duration grandi, usa toSeconds() o toMinutes().
Usa Duration.between(startTime, endTime). Se endTime è minore di startTime (turno notturno), Duration sarà negativa. Aggiungi 24 ore: duration.plusHours(24), se si presume che endTime sia il giorno successivo.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche