Clase Java ZonedDateTime

ZonedDateTime es una clase importante en la API de fecha y hora introducida en Java 8 (paquete java.time). Representa una fecha y hora con zona horaria. Esta clase combina LocalDateTime y ZoneId, y puede representar con precisión un punto en el tiempo en una zona horaria específica.

Características principales

  • Incluye fecha (año, mes, día)
  • Incluye hora (hora, minuto, segundo, nanosegundo)
  • Incluye información de zona horaria
  • Es una clase inmutable y segura para subprocesos
  • Admite conversión de zona horaria y ajuste automático del horario de verano

Formas de crear ZonedDateTime

1. Crear con la hora actual

Ejemplo

// Obtener la fecha y hora de la zona horaria predeterminada del sistema
ZonedDateTime now = ZonedDateTime.now();

// Obtener la fecha y hora actual de la zona horaria especificada
ZonedDateTime nowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

2. Crear a partir de componentes

Ejemplo

// Especificar año, mes, día, hora, minuto, segundo y zona horaria
ZonedDateTime customDateTime = ZonedDateTime.of(
    2023, 12, 25, 15, 30, 0, 0,
    ZoneId.of("America/New_York")
);

3. Combinar LocalDateTime y ZoneId

Ejemplo

LocalDateTime localDateTime = LocalDateTime.of(2023, 6, 15, 10, 30);
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime parisTime = ZonedDateTime.of(localDateTime, zoneId);

Métodos de operación comunes

1. Obtener información de fecha y hora

Ejemplo

ZonedDateTime zdt = ZonedDateTime.now();

int year = zdt.getYear();          // año
Month month = zdt.getMonth();      // mes
int day = zdt.getDayOfMonth();     // día
int hour = zdt.getHour();          // hora
int minute = zdt.getMinute();      // minuto
int second = zdt.getSecond();      // segundo
ZoneId zone = zdt.getZone();       // zona horaria

2. Operaciones de suma y resta de tiempo

Ejemplo

ZonedDateTime zdt = ZonedDateTime.now();

// sumar 1 día
ZonedDateTime tomorrow = zdt.plusDays(1);

// restar 2 horas
ZonedDateTime twoHoursEarlier = zdt.minusHours(2);

// sumar 3 semanas
ZonedDateTime threeWeeksLater = zdt.plusWeeks(3);

3. Conversión de zona horaria

Ejemplo

ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

// Convertir a hora de Nueva York
ZonedDateTime newYorkTime = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));

// Convertir a hora UTC
ZonedDateTime utcTime = tokyoTime.withZoneSameInstant(ZoneOffset.UTC);

Ejemplos de aplicaciones prácticas

1. Calcular la diferencia horaria entre dos zonas horarias

Ejemplo

ZonedDateTime londonTime = ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime sydneyTime = ZonedDateTime.now(ZoneId.of("Australia/Sydney"));

// Calcular la diferencia en horas
long hoursBetween = ChronoUnit.HOURS.between(londonTime, sydneyTime);
System.out.println("Diferencia horaria actual entre Londres y Sídney: " + hoursBetween + "horas");

2. Manejar horarios de reuniones entre zonas horarias

Ejemplo

// La reunión en Nueva York es a las 3 p.m.
ZonedDateTime meetingTimeNY = ZonedDateTime.of(
    LocalDate.now(),
    LocalTime.of(15, 0),
    ZoneId.of("America/New_York")
);

// Convertir a hora de Tokio
ZonedDateTime meetingTimeTokyo = meetingTimeNY.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("Los asistentes en Tokio deben estar a la hora local: " + meetingTimeTokyo);

3. Manejo del horario de verano

Ejemplo

// Hora en Nueva York antes y después del cambio de horario de verano
ZonedDateTime beforeDST = ZonedDateTime.of(
    LocalDateTime.of(2023, 3, 11, 1, 30),
    ZoneId.of("America/New_York")
);

ZonedDateTime afterDST = beforeDST.plusHours(1);
System.out.println("Diferencia horaria real: " +
    Duration.between(beforeDST, afterDST).toHours() + "horas");

Conversión de ZonedDateTime con otras clases de fecha y hora

1. Convertir a Instant

Ejemplo

ZonedDateTime zdt = ZonedDateTime.now();
Instant instant = zdt.toInstant();  // Convertir a marca de tiempo UTC

2. Convertir a LocalDateTime

Ejemplo

ZonedDateTime zdt = ZonedDateTime.now();
LocalDateTime ldt = zdt.toLocalDateTime();  // Se pierde la información de zona horaria

3. Crear desde Instant

Ejemplo

Instant instant = Instant.now();
ZonedDateTime zdt = instant.atZone(ZoneId.of("Asia/Shanghai"));

Ejemplo integral

Ejemplo

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        // 1. Obtener la hora actual de la zona horaria actual
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("Hora de la zona horaria actual: " + now);
       
        // 2. Obtener la hora actual de una zona horaria específica
        ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("Hora de Tokio: " + tokyoTime);
       
        // 3. Crear una fecha y hora específica con zona horaria
        ZonedDateTime specificTime = ZonedDateTime.of(
            2023, 5, 15, 10, 30, 0, 0,
            ZoneId.of("America/New_York")
        );
        System.out.println("Hora específica en Nueva York: " + specificTime);
       
        // 4. Conversión de zona horaria
        ZonedDateTime londonTime = specificTime.withZoneSameInstant(ZoneId.of("Europe/London"));
        System.out.println("Hora correspondiente en Londres: " + londonTime);
       
        // 5. Salida formateada
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
        System.out.println("Hora formateada: " + now.format(formatter));
       
        // 6. Obtener información de cada parte
        System.out.println("Zona horaria: " + now.getZone());
        System.out.println("Año: " + now.getYear());
        System.out.println("Mes: " + now.getMonth());
        System.out.println("Hora: " + now.getHour());
    }
}

La salida es similar a lo siguiente:

当前时区时间: 2025-05-01T11:29:07.411467+08:00[Asia/Shanghai]
东京时间: 2025-05-01T12:29:07.417938+09:00[Asia/Tokyo]
纽约特定时间: 2023-05-15T10:30-04:00[America/New_York]
对应的伦敦时间: 2023-05-15T15:30+01:00[Europe/London]
格式化时间: 2025-05-01 11:29:07 CST
时区: Asia/Shanghai
年份: 2025
月份: MAY
小时: 11

Mejores prácticas

  1. Almacenamiento y transmisión: al almacenar en bases de datos o transmitir por red, se recomienda usar Instant o ZonedDateTime en hora UTC
  2. Visualización: convierta a la zona horaria local solo al mostrar en la interfaz de usuario
  3. Comparación: al comparar horas de diferentes zonas horarias, convierta primero a la misma zona horaria o a Instant
  4. Horario de verano: use siempre el ID de zona horaria completo (como "America/New_York") en lugar de un simple desplazamiento (como "-05:00")

ZonedDateTime es una herramienta poderosa para manejar aplicaciones sensibles a la zona horaria; usarlo correctamente puede evitar muchos problemas comunes de fecha y hora.

Métodos de fábrica estáticos

Método Descripción Ejemplo
static ZonedDateTime now() Obtener la fecha y hora actual de la zona horaria actual ZonedDateTime.now()
static ZonedDateTime now(ZoneId zone) Obtener la fecha y hora actual de la zona horaria especificada ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
static ZonedDateTime of(int year, int month, int day, int hour, int minute, int second, int nano, ZoneId zone) Crear especificando parámetros ZonedDateTime.of(2023, 6, 15, 14, 30, 0, 0, ZoneId.of("GMT+8"))
static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) Crear combinando LocalDate, LocalTime y zona horaria ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.systemDefault())
static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) Crear desde LocalDateTime y zona horaria ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("America/New_York"))
static ZonedDateTime ofInstant(Instant instant, ZoneId zone) Crear desde Instant y zona horaria ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("UTC"))
static ZonedDateTime parse(CharSequence text) Analizar desde una cadena ZonedDateTime.parse("2023-06-15T14:30:45+08:00[Asia/Shanghai]")
static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) Analizar usando un formato específico ZonedDateTime.parse("2023-06-15 14:30 CST", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm z"))

Obtener información de fecha y hora

Método Descripción Ejemplo
int getYear() Obtener el año 2023
Month getMonth() Obtener el mes (enum Month) Month.JUNE
int getMonthValue() Obtener el valor del mes (1-12) 6
int getDayOfMonth() Obtener el día del mes 15
int getDayOfYear() Obtener el día del año 166
DayOfWeek getDayOfWeek() Obtener el día de la semana (enum DayOfWeek) DayOfWeek.THURSDAY
int getHour() Obtener la hora (0-23) 14
int getMinute() Obtener el minuto (0-59) 30
int getSecond() Obtener el segundo (0-59) 45
int getNano() Obtener el nanosegundo 0
ZoneId getZone() Obtener la zona horaria Asia/Shanghai
ZoneOffset getOffset() Obtener el desplazamiento de zona horaria +08:00

Operaciones de fecha y hora

Método Descripción Ejemplo
ZonedDateTime plusDays(long days) Agregar días zdt.plusDays(5)
ZonedDateTime plusHours(long hours) Agregar horas zdt.plusHours(2)
ZonedDateTime plusMinutes(long minutes) Agregar minutos zdt.plusMinutes(30)
ZonedDateTime plusSeconds(long seconds) Agregar segundos zdt.plusSeconds(45)
ZonedDateTime plusNanos(long nanos) Agregar nanosegundos zdt.plusNanos(1000000)
ZonedDateTime minusDays(long days) Restar días zdt.minusDays(5)
ZonedDateTime minusHours(long hours) Restar horas zdt.minusHours(2)
ZonedDateTime minusMinutes(long minutes) Restar minutos zdt.minusMinutes(30)
ZonedDateTime minusSeconds(long seconds) Restar segundos zdt.minusSeconds(45)
ZonedDateTime minusNanos(long nanos) Restar nanosegundos zdt.minusNanos(1000000)
ZonedDateTime withYear(int year) Modificar el año zdt.withYear(2024)
ZonedDateTime withMonth(int month) Modificar el mes zdt.withMonth(12)
ZonedDateTime withDayOfMonth(int day) Modificar el día del mes zdt.withDayOfMonth(1)
ZonedDateTime withHour(int hour) Modificar la hora zdt.withHour(0)
ZonedDateTime withMinute(int minute) Modificar el minuto zdt.withMinute(0)
ZonedDateTime withSecond(int second) Modificar el segundo zdt.withSecond(0)
ZonedDateTime withNano(int nano) Modificar el nanosegundo zdt.withNano(0)
ZonedDateTime withZoneSameInstant(ZoneId zone) Convertir zona horaria (manteniendo el mismo instante) zdt.withZoneSameInstant(ZoneId.of("UTC"))
ZonedDateTime withZoneSameLocal(ZoneId zone) Convertir zona horaria (manteniendo la hora local) zdt.withZoneSameLocal(ZoneId.of("UTC"))

Métodos de conversión

Método Descripción Ejemplo
LocalDate toLocalDate() Convertir a LocalDate zdt.toLocalDate()
LocalTime toLocalTime() Convertir a LocalTime zdt.toLocalTime()
LocalDateTime toLocalDateTime() Convertir a LocalDateTime zdt.toLocalDateTime()
OffsetDateTime toOffsetDateTime() Convertir a OffsetDateTime zdt.toOffsetDateTime()
Instant toInstant() Convertir a Instant zdt.toInstant()

Métodos de comparación

Método Descripción Ejemplo
boolean isAfter(ChronoZonedDateTime<?> other) Si es después de la fecha y hora especificadas zdt1.isAfter(zdt2)
boolean isBefore(ChronoZonedDateTime<?> other) Si es antes de la fecha y hora especificadas zdt1.isBefore(zdt2)
boolean isEqual(ChronoZonedDateTime<?> other) Si es igual a la fecha y hora especificadas zdt1.isEqual(zdt2)
int compareTo(ChronoZonedDateTime<?> other) Comparar dos fechas y horas zdt1.compareTo(zdt2)

Formateo y conversión a cadenas

Métodos Descripción Ejemplo
String format(DateTimeFormatter formatter) Formatear como cadena zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)
String toString() Convertir a cadena en formato ISO "2023-06-15T14:30:45+08:00[Asia/Shanghai]"
Otras extensiones