W3docs

Java LocalTime

Representa horas sin fechas ni zonas horarias en Java con LocalTime.

LocalTime es el espejo de LocalDate: una hora del día — hora, minuto, segundo, nanosegundo — sin fecha y sin zona horaria. Representa la misma lectura del reloj en cualquier día del calendario en cualquier lugar: LocalTime.of(9, 30) son las nueve y media en cualquier día en cualquier ciudad.

Ese es el tipo correcto para una hora recurrente del día — una tienda que abre a las 09:30, un trabajo tipo cron diario a las 03:15, una reunión que comienza a las 14:00 independientemente de la fecha. No es el tipo correcto para "el momento en que el usuario hizo clic en enviar a las 14:30 de hoy" — eso necesita una fecha y probablemente una zona. Los dos combinados forman un LocalDateTime, el tema del próximo capítulo.

Creación

LocalTime now = LocalTime.now();                              // current time in the JVM default zone
LocalTime nine = LocalTime.of(9, 0);                          // hour, minute
LocalTime nineThirty = LocalTime.of(9, 30, 15);               // hour, minute, second
LocalTime nineThirtyNanos = LocalTime.of(9, 30, 15, 500_000_000);   // + nanosecond (0 ..999_999_999)
LocalTime parsed = LocalTime.parse("09:30:15");               // ISO-8601 HH:mm[:ss[.nnnnnnnnn]]

Las constantes predefinidas son útiles para condiciones de límite:

LocalTime.MIDNIGHT     // 00:00
LocalTime.NOON         // 12:00
LocalTime.MIN          // 00:00:00.000000000
LocalTime.MAX          // 23:59:59.999999999

MIN y MAX son especialmente útiles cuando se combinan con un LocalDate para abarcar un día completo: LocalDateTime.of(date, LocalTime.MIN) es "medianoche al inicio de la fecha"; LocalTime.MAX es el último nanosegundo representable del día.

Resolución: nanosegundos

LocalTime es preciso hasta el nanosegundo — resolución de nueve campos (1 segundo = 1.000.000.000 ns). En la mayoría de los sistemas operativos la resolución real del reloj es de milisegundos (1.000.000 ns cada uno) o microsegundos (1.000 ns cada uno); la precisión extra está ahí para que el tipo no pierda información al interactuar con sistemas que tienen relojes de mayor resolución.

Accesores directos:

time.getHour();           // 0-23
time.getMinute();         // 0-59
time.getSecond();         // 0-59
time.getNano();           // 0-999_999_999

No existe getMilli(); si quieres milisegundos, divide el nano: time.getNano() / 1_000_000.

24 horas, sin AM/PM

LocalTime es internamente de 24 horas. LocalTime.of(13, 0) es "la 1 PM" y no existe AM/PM en el tipo. Analizar cadenas con "AM"/"PM" requiere un DateTimeFormatter personalizado (el capítulo de Análisis de Fechas cubre esto) — el parse predeterminado es solo ISO-8601 de 24 horas.

Aritmética y modificaciones

La misma forma fluida que LocalDate:

time.plusHours(2);
time.plusMinutes(30);
time.plusSeconds(45);
time.plusNanos(500_000);

time.withHour(14);                                            // replace one field
time.withMinute(0);

El comportamiento de desbordamiento: cada método plus/minus en LocalTime da la vuelta silenciosamente a la medianoche. LocalTime.of(23, 0).plusHours(2) es 01:00, no "mañana a las 01:00" — no existe "mañana" en LocalTime. Si necesitas saber si ocurrió un desbordamiento, usa LocalDateTime o haz los cálculos tú mismo:

LocalTime late = LocalTime.of(23, 0);
LocalTime later = late.plusHours(2);                          // 01:00 — silently wrapped
// To detect wrap: compare the new value's getHour with what you expected, or use LocalDateTime.

Este desbordamiento está documentado y es intencional, pero es un punto delicado si lo olvidas. Para cálculos de "¿cuándo termina este turno?" que pueden cruzar la medianoche, el tipo correcto es LocalDateTime, no LocalTime.

Comparación

time.isBefore(other);
time.isAfter(other);
time.compareTo(other);
time.equals(other);

Ordenación lexicográfica por hora:minuto:segundo:nano. LocalTime implementa Comparable<LocalTime>, por lo que puedes ordenar una lista de horas o usarlo directamente como clave de TreeMap.

Distancia

Duration.between y ChronoUnit.X.between funcionan ambos:

Duration d = Duration.between(start, end);
long minutes = ChronoUnit.MINUTES.between(start, end);
long seconds = ChronoUnit.SECONDS.between(start, end);

El signo: positivo cuando end es posterior a start, negativo en caso contrario. La misma advertencia de desbordamiento aplica — Duration.between(LocalTime.of(23, 0), LocalTime.of(1, 0)) son −22 horas, no +2 horas; la API trata 01:00 como anterior a 23:00 del mismo día nocional. Para "el turno pasó la medianoche," la aritmética basada en LocalDateTime es la herramienta correcta.

Combinación con LocalDate

Con frecuencia convertirás a una fecha con hora:

LocalDate date = LocalDate.of(2025, 11, 4);
LocalTime time = LocalTime.of(9, 30);

LocalDateTime dt = date.atTime(time);                         // 2025-11-04T09:30
LocalDateTime dt2 = time.atDate(date);                        // same thing

atTime / atDate son los métodos puente. El resultado es un LocalDateTime — todavía sin zona, pero ahora anclado a un día calendario. El próximo capítulo lo lleva más lejos.

Un ejemplo práctico: un pequeño ayudante de programación

El programa a continuación usa LocalTime para una tarea de tipo agenda diaria: definir una ventana de "horario de oficina", verificar si un momento dado cae dentro de ella, calcular cuánto tiempo falta hasta la próxima apertura y demostrar el problema del desbordamiento a la medianoche.

java— editable, runs on the server

Lo que se puede extraer de la ejecución:

  • LocalTime impreso como 09:00, 17:30, 12:30 — la forma canónica ISO-8601 de 24 horas. Sin AM/PM en el tipo. Si necesitas mostrar "5:30 PM" a un usuario, el capítulo de Formato de Fechas tiene el formateador para eso; el tipo en sí no lo conoce.
  • La verificación "¿la hora está dentro de la ventana?" usó !isBefore(open) && !isAfter(close). Ese es el idioma de intervalo semiabierto-vs-cerrado — ambos extremos están incluidos. Para "estrictamente dentro," cambia a las formas sin negar.
  • Duration.between(LocalTime.of(22, 0), LocalTime.of(2, 0)) devolvió PT-20H, no PT4H. LocalTime no tiene noción de "día siguiente" — cuando end es anterior a start en términos del reloj, la duración se vuelve negativa. Para un turno que cruza la medianoche, cambia las entradas a LocalDateTime y deja que las fechas resuelvan la ambigüedad. Este es el mayor punto problemático de LocalTime.
  • LocalTime.of(23, 30).plusHours(2) devolvió 01:30. El desbordamiento es silencioso — sin excepción, sin bandera, sin arrastre a la fecha. Si necesitas saber "¿hubo desbordamiento?", usa LocalDateTime. Si genuinamente quieres aritmética de reloj módulo 24 (una agenda recurrente, por ejemplo), el desbordamiento es el comportamiento correcto.
  • date.atTime(time) fue el puente canónico a LocalDateTime. El espejo time.atDate(date) produce el mismo resultado. Los usarás constantemente cuando leas una hora de una fuente y una fecha de otra, y luego las combines en el único objeto que la API de destino necesita.

Qué sigue

El próximo capítulo, Java LocalDateTime, combina LocalDate y LocalTime en el tercer tipo "local": una fecha y una hora, todavía sin zona horaria adjunta. Esa es la unidad natural para "esto ocurrió a las 14:30 del 4 de noviembre" cuando la zona es irrelevante o se registra por separado.

Práctica

Práctica
¿Qué devuelve `LocalTime.of(23, 0).plusHours(3)`, y por qué?
¿Qué devuelve `LocalTime.of(23, 0).plusHours(3)`, y por qué?
Was this page helpful?