Duration — una clase inmutable del paquete java.time que representa la duración entre dos momentos en el tiempo en segundos y nanosegundos. Duration mide cantidades de tiempo basadas en tiempo — horas, minutos, segundos, milisegundos y nanosegundos. Según la especificación de Oracle Java 17 (2024), a diferencia de Period (que mide años-meses-días), Duration trabaja con unidades de tiempo precisas y no depende del calendario.
Puntos clave
Duration es una clase que modela la cantidad de tiempo en segundos y nanosegundos. Representa una duración basada en tiempo, es decir, un número físico de segundos no vinculado a un calendario. Duration se puede pensar como “125 minutos” o “2 horas 5 minutos” — a diferencia de Period, que diría “2 meses”.
La representación interna de Duration consta de dos campos: long seconds (segundos) e int nanos (nanosegundos, de 0 a 999999999). El valor puede ser negativo — lo que significa una duración “hacia atrás” en el tiempo. El valor máximo es ±31557014167219200 segundos.
Según Baeldung (2024), Duration es una clase clave para calcular la duración de operaciones, configurar tiempos de espera y medir el rendimiento. Duration es inmutable y thread-safe, lo que permite su uso en entornos multiproceso sin sincronización.
La clase implementa las interfaces Comparable, TemporalAmount y TemporalUnit. TemporalAmount permite usar Duration en los métodos plus/minus de las clases LocalTime, LocalDateTime, Instant y ZonedDateTime.
La principal diferencia es que Duration mide el número exacto de segundos (basado en tiempo), mientras que Period mide unidades de calendario (basado en fechas): años, meses, días. Duration dice: “han pasado 86400 segundos”. Period dice: “ha pasado 1 día”. La diferencia se hace evidente durante los cambios de hora de verano — 1 día en Period siempre es 1 día calendario, mientras que 86400 segundos en Duration pueden corresponder a 23 o 25 horas durante el DST.
Duration se usa para medir tiempo físico: tiempos de espera de conexión, tiempo de ejecución de consultas, intervalos entre dos Instant. Period se usa para cálculos de calendario: edad de una persona (Period.between(dateOfBirth, today)), duración de un contrato.
Duration trabaja con segundos y nanosegundos, por lo que se puede dividir en partes (horas, minutos). Period trabaja con años, meses y días — unidades de calendario indivisibles. Según Oracle Java Tutorial (2024), la elección entre Duration y Period depende del tipo de tarea: tiempo preciso vs fechas de calendario.
La forma más común es Duration.between(Temporal start, Temporal end). Temporal puede ser Instant, LocalTime, LocalDateTime, ZonedDateTime — cualquier tipo que implemente Temporal. El método devuelve una Duration que representa la diferencia start - end (puede ser negativa).
Métodos de fábrica estáticos: Duration.ofSeconds(long), ofMinutes(long), ofHours(long), ofDays(long), ofMillis(long), ofNanos(long). También existe of(long amount, TemporalUnit unit) para unidades arbitrarias — ChronoUnit.HOURS, ChronoUnit.MINUTES y otras.
El método parse(CharSequence) acepta una cadena en formato ISO-8601: “PT1H30M” (1 hora 30 minutos), “PT45S” (45 segundos), “P2DT3H” (2 días 3 horas). La cadena siempre comienza 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 admite un conjunto completo de operaciones aritméticas. Los métodos plus(Duration) y minus(Duration) suman o restan otra duración. Los métodos plusDays(), plusHours(), plusMinutes(), plusSeconds(), plusMillis(), plusNanos() — para agregar unidades específicas.
Para multiplicación y división, se usan multipliedBy(long) y dividedBy(long). Duration.multipliedBy(2) duplica la duración. Duration.dividedBy(3) divide en tres partes redondeando hacia abajo. El método negated() invierte el signo — lo positivo se vuelve negativo y viceversa.
El método abs() devuelve una Duration con valor absoluto (positivo). isNegative() y isZero() son comprobaciones. toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos() convierten a las unidades correspondientes.
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 la interfaz Comparable, lo que permite comparar duraciones de forma natural. El método compareTo() devuelve un número negativo, cero o positivo. isNegative() y isZero() son comprobaciones rápidas. Para comparación explícita, use equals() — dos Duration son iguales si coinciden sus segundos y nanosegundos.
Dado que Duration puede ser negativa, las comparaciones “mayor que” o “menor que” funcionan teniendo en cuenta el signo. -5 minutos es menor que 2 minutos. El método abs() es útil para comparar longitudes “absolutas” independientemente de la dirección.
En Kotlin, Duration admite operadores de comparación mediante sobrecarga de operadores: a < b, a > b, a <= b. También están disponibles plus y minus como operadores: a + b, a - b.
val short = Duration.ofMinutes(5)
val long = Duration.ofMinutes(10)
if (short < long) {
Log.d("Duration", "5 min is less than 10")
}
val negative = Duration.ofMinutes(-3)
Log.d("Duration", "Negative: ${negative.isNegative()}")
El primer ejemplo es configurar la sincronización periódica con el servidor. Duration se utiliza para calcular el intervalo entre sincronizaciones y verificar si se ha excedido el límite de tiempo sin actualización.
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)
}
El segundo ejemplo es medir el tiempo de ejecución de una operación para registrar el rendimiento.
fun measureExecution(
tag: String,
block: () -> Unit
) {
val start = Instant.now()
block()
val duration = Duration.between(start, Instant.now())
Log.d(tag, "Executed in ${duration.toMillis()} ms")
}
El tercer ejemplo es calcular el tiempo restante de un temporizador (por ejemplo, la cuenta regresiva hasta el final de una promoción).
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
}
El método toString() devuelve Duration en formato ISO-8601: “PT1H30M” (1 hora 30 minutos), “PT45.5S” (45.5 segundos). Este formato es conveniente para el intercambio entre máquinas, pero no para mostrarlo al usuario.
Para un formato legible por humanos, use toDays(), toHours(), toMinutes(), toSeconds() seguido de la construcción manual de la cadena. Por ejemplo: “${days} d ${hours} h ${minutes} min”. Tenga en cuenta que toHours() devuelve el número total de horas, no las horas dentro del día.
Para desglosar Duration en componentes, use la fórmula: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. Según Apache Commons Lang (2024), la librería DurationFormatUtils proporciona capacidades adicionales de formateo.
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")
}
}
El primer error es confundir Duration y Period al trabajar con fechas. Duration mide segundos, por lo que Duration.ofDays(1) siempre son 24 horas (86400 segundos), independientemente de los cambios de hora de verano. Si necesita un día calendario, use Period.ofDays(1).
El segundo error es perder nanosegundos durante la conversión. Duration puede almacenar nanosegundos, pero toMillis() y toSeconds() los descartan. Para cálculos precisos, use toNanos() o trabaje con Duration directamente sin convertir a primitivos.
El tercer error es ignorar Duration negativa. Duration.between(start, end) devuelve start - end. Si start está después de end, Duration será negativa. El método abs() ayuda a obtener el valor absoluto, e isNegative() verifica el orden de los argumentos.
El cuarto error es un formateo incorrecto de Duration para la interfaz de usuario. Duration.toString() devuelve ISO-8601, que no es legible. Siempre formatee Duration manualmente para mostrarlo al usuario usando toHours(), toMinutes() y toSeconds() con el resto correcto de la división.
Preguntas frecuentes
Sí, Duration puede ser negativa. Duration.between(start, end) devuelve start - end. Si start está después de end, Duration será negativa. Use abs() para obtener el valor absoluto o isNegative() para comprobarlo.
Use el método plus(Duration) o el operador + en Kotlin: duration1 + duration2. El resultado es una nueva Duration. El método minus(Duration) resta una duración de otra. Todas las operaciones son inmutables y devuelven un nuevo objeto.
Duration.ofDays(1) siempre son 24 horas (86400 segundos). Period.ofDays(1) es 1 día calendario, que durante el DST puede ser de 23 o 25 horas. Para cálculos de tiempo precisos, use Duration; para cálculos de calendario, use Period.
Use el método toMillis(). Devuelve un long — el número de milisegundos en la Duration. Para nanosegundos, use toNanos(). Atención: toNanos() puede desbordar long en valores > 292 años. Para Duration grandes, use toSeconds() o toMinutes().
Use Duration.between(startTime, endTime). Si endTime es menor que startTime (turno nocturno), Duration será negativa. Agregue 24 horas: duration.plusHours(24), si se asume que endTime es el día siguiente.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también