W3docs

Java Duration

Representa intervalos de tiempo (horas, minutos, segundos) en Java con Duration.

Duration representa una longitud de tiempo medida en segundos y nanosegundos. "Dos horas." "Quinientos milisegundos." "Cuarenta y cinco minutos." Internamente son dos números — un long seconds y un int nanos — y toda operación sobre él es aritmética de enteros. No conoce calendarios, meses ni horario de verano (DST); si le indicas 24 horas, significa exactamente 86.400 segundos, independientemente de si esas 24 horas abarcan un cambio de horario.

Este es el tipo correcto para: medición de tiempos, timeouts, reintentos con retroceso exponencial, "esperar como máximo X segundos," cualquier situación donde la respuesta es un intervalo de tiempo real. El tipo complementario para longitudes de calendario ("un mes," "dos años") es Period, que se trata en el siguiente capítulo.

Creación

Tres 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) es la fábrica que la mayoría de la gente usa y que la mayoría malentiende. Produce exactamente n * 24 * 3600 segundos. En un día con cambio de horario, eso no es lo mismo que "el día siguiente a la misma hora del reloj." Para un "un día después" con forma de calendario, LocalDate.plusDays(1) o Period.ofDays(1) son las herramientas correctas.

El formato de cadena es la duración ISO-8601: PT1H30M45S equivale a una hora, treinta minutos y cuarenta y cinco segundos. El prefijo PT es obligatorio (P = Period, T = Time). Para componentes sub-segundo, la forma es PT0.5S o PT0.000000001S. Duration cubre todo por debajo del día; los periodos (año, mes, día) pertenecen 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 devuelve un nuevo Duration (la inmutabilidad que encontramos desde LocalDate en adelante).

Los accesores de conversión:

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)

Los métodos toX() devuelven un único long con el total en esa unidad, truncando. Los métodos getX() devuelven el desglose en bruto. Son cosas distintas; confundirlos es el error más común con Duration.

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

Para formatear "X minutos Y segundos", usa ambos:

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

O, desde Java 9, los helpers de desglose 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

Estos son los que necesitas para "mostrar 1h 23m 45s" sin hacer el módulo manualmente.

Comparación

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

Duration implementa Comparable<Duration>. El orden es con signo — una duración negativa es menor que cero, que es menor que una duración positiva.

Distancia entre dos Temporals

La fábrica Duration.between(start, end) es la que usarás con mayor frecuencia:

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

Acepta cualquier par de valores Temporal que soporten unidades basadas en tiempo. LocalDate (solo fecha) noDuration.between(date1, date2) lanza DateTimeException porque una fecha no tiene componente de reloj. Para distancias de calendario, usa Period.between(date1, date2) o ChronoUnit.DAYS.between(date1, date2).

La convención de signo: positivo si end es posterior a start, negativo en caso contrario.

Añadir a otros temporales

Duration es un TemporalAmount, por lo que cualquier Temporal lo acepta mediante plus/minus:

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

Añadir un Duration a un LocalDate lanza una excepción — por la misma razón que antes, no tiene componente de reloj. El compilador no detecta esto; la llamada falla en tiempo de ejecución. Si te encuentras queriendo hacerlo, casi con toda certeza querías usar Period.

Un ejemplo práctico: tiempo, formato y retroceso

El programa siguiente mide el tiempo transcurrido de una pequeña tarea, lo imprime en formato legible usando los helpers toXxxPart, calcula un esquema de retroceso exponencial y demuestra la frontera entre Duration y Period mostrando tanto Duration.between sobre Instants como Period.between sobre LocalDates para el mismo intervalo conceptual.

java— editable, runs on the server

Lo que se aprende de la ejecución:

  • El bloque Thread.sleep(125) se midió como PT0.125-algo-S — la variación real del sleep es variabilidad de la máquina real. Duration.between(t0, t1) fue la llamada correcta: dos Instants, sin zona horaria necesaria, respuesta exacta a la resolución del reloj del sistema.
  • Los helpers toXxxPart() dieron enteros limpios para "la parte de horas," "la parte de minutos," "la parte de segundos," "la parte de milisegundos." Sin ellos habría que hacer aritmética modular total / 3600 y (total % 3600) / 60 a mano. Úsalos siempre que necesites formatear una duración para un humano.
  • El bucle de retroceso exponencial escaló la duración con multipliedBy(2) e imprimió cada resultado. La forma de cadena ISO-8601 (PT2S, PT4S, PT8S, ...) es lo que imprime Duration.toString; es concisa e inequívoca, ideal para logs.
  • El bloque "Jan 1 → Apr 1 en tres formas" mostró la frontera entre Duration y Period. Period.between(start, end) devolvió P3M — tres meses de calendario. Duration.between sobre los instantes UTC equivalentes devolvió un conteo de tiempo real (90 días). Ambos son correctos; responden preguntas distintas. Elige el que cuyo significado coincida con la intención de tu código.
  • El bloque final intentó Duration.between(LocalDate, LocalDate) y obtuvo DateTimeException. El sistema de tipos sabe que una fecha no tiene componente de reloj, por lo que rechaza calcular una duración basada en reloj. La solución es (1) adjuntar tiempos (startDate.atStartOfDay(zone)), o (2) usar Period.between si lo que realmente necesitas es un conteo de calendario. La excepción es el diseño correcto: las respuestas silenciosas a esa pregunta serían engañosas.

Qué viene después

Duration es la longitud en segundos y nanosegundos. El siguiente capítulo, Java Period, es la longitud en años, meses y días — el complemento con forma de calendario. Los dos nunca se mezclan: Duration no conoce los meses, Period no conoce las horas, y cualquier código que maneje ambos recurre a uno u otro dependiendo de si la respuesta debe seguir el calendario o el reloj de pared.

Práctica

Práctica
Quieres reintentar una solicitud HTTP después de 'un día,' es decir, '24 horas a partir de ahora independientemente del horario de verano.' ¿Qué tipo y llamada hacen eso?
Quieres reintentar una solicitud HTTP después de 'un día,' es decir, '24 horas a partir de ahora independientemente del horario de verano.' ¿Qué tipo y llamada hacen eso?
Was this page helpful?