Fechas en Java 8+¶
Actualmente en el Jdk de Java hay dos Apis para la gestión de calendarios, fechas y horas que puede usar el programador. El primero de ellos es un api obsoleto que será eliminado en un futuro de Java, y corresponde con el uso de java.util.Date
, java.util.Calendar
y relacionados. Estos objetos están prácticamente desde el inicio de Java y a través de la evolución del lenguaje y su uso en entornos cada vez más diversos se han quedado desfasados.
Para remediar los puntos negativos, en la versión de Jdk 8 y posteriores, el lenguaje incorpora un nuevo api para la gestión de tiempo, denominado de forma común por java.time
por el paquete en el que están ubicadas las clases que lo conforman
java.time¶
En marzo de 2014 apareció la versión estándar de Java 8 y con ella estas nuevas clases especializadas que solucionan la mayor parte de los problemas de las clases tradicionales, e incluyen soporte automático para cosas como años bisiestos, zonas horarias y cambio automático de zona horaria
Las principales clases son
clase | descripción |
---|---|
LocalDate | representa a fechas sin la hora y nos facilita su manejo para declararlas, sumar y restar fechas y compararlas. |
LocalTime | es idéntica a la anterior pero para el manejo de horas, sin ninguna fecha asociada, pudiendo así compararlas, sumar o restar tiempo a las mismas |
LocalDateTime | como puedes suponer, es una combinación de las dos anteriores, que permite hacer lo mismo con fechas y horas simultáneamente. |
Instant | es muy parecida a la anterior pero a la vez muy diferente. Se usa para almacenar un punto determinado en el tiempo, o sea con fecha y hora, pero guarda su valor como un timestamp de UNIX, es decir, en nanosegundos desde el epoch de UNIX (1/1/1970 a las 00:00) y usando la zona horaria UTC. Es muy útil para manejar momentos en el tiempo de manera neutra e intercambiarlo entre aplicaciones y sistemas, por lo que lo verás utilizado muy a menudo. |
ZonedDateTime | esta clase es como la LocalDateTime pero teniendo en cuenta una zona horaria concreta, ya que las anteriores no la tienen en cuenta. |
Period | esta clase auxiliar nos ayuda a obtener diferencias entre fechas en distintos periodos (segundos, minutos, días...) y también a añadir esas diferencias a las fechas. |
Duration | esta es muy parecida a la anterior pero para manejo de horas exclusivamente |
Clock | Un reloj que proporciona acceso al instante actual, fecha y hora utilizando una zona horaria |
MonthDay | Un mes al día en el sistema de calendario ISO-8601, como –12-03. |
OffsetDateTime | Una fecha y hora con una compensación de UTC / Greenwich en el sistema de calendario ISO-8601, como 2007-12-03T10: 15: 30 + 01: 00. |
Year | Un año en el sistema de calendario ISO-8601, como 2007 |
YearMonth | Un año-mes en el sistema de calendario ISO-8601, como 2007-12. |
ZoneId | Una identificación de zona horaria, como Europa / París |
ZoneOffset | Un desplazamiento de zona horaria de Greenwich / UTC, como +02: 00. |
Creación de fechas¶
Para la creación de fechas tenemos que saber si necesitamos:
- la fecha
- la hora
- la fecha y la hora
Para el manejo de fechas tenemos principalmente de 3 métodos:
now()
: crean instancias nuevas a partir de la fecha y hora actual.of()
: construyen fechas y horas a partir de sus parteswith()
: modifican la fecha u hora actual en función del parámetro que se le pase
//creación de fechas
LocalDate localDate1 = LocalDate.now();
LocalDate localDate2 = LocalDate.of(2024, 02, 20);
LocalDate localDate4 = LocalDate.of(2024, Month.FEBRUARY, 20);
LocalDate localDate3 = LocalDate.parse("2024-02-20");
//Creación de horas
LocalTime horaActual = LocalTime.now();
LocalTime horaEspecifica = LocalTime.of(15, 30, 0);
LocalTime horaParseada = LocalTime.parse("13:45:30");
//fecha/hora
LocalDateTime fechaHoraActual = LocalDateTime.now();
LocalDateTime fechaHoraEspecifica = LocalDateTime.of(2024, 4, 11, 15, 30, 0);
LocalDateTime fechaHoraParseada = LocalDateTime.parse("2024-04-11T13:45:30");
El método now()
está disponible en varias clases, y su resultado es diferente
System.out.println("La fecha actual es: " + LocalDate.now());
System.out.println( "La hora actual es: " + LocalTime.now() );
System.out.println( "La fecha y hora actuales son: " + LocalDateTime.now() );
System.out.println( "El instante actual es: " + Instant.now() );
System.out.println( "La fecha y hora actuales con zona horaria son: " + ZonedDateTime.now() );
/*
La fecha actual es: 2024-04-11
La hora actual es: 13:04:16.928467900
La fecha y hora actuales son: 2024-04-11T13:04:16.928467900
El instante actual es: 2024-04-11T11:04:16.928467900Z
La fecha y hora actuales con zona horaria son: 2024-04-11T13:04:16.928467900+02:00[Europe/Madrid]
*/
Partes de Fecha/hora¶
Tenemos variedad de método que permiten acceder a las partes de una fecha/hora
LocalDateTime fechaHoraActual = LocalDateTime.now();
int year=fechaHoraActual.getYear();
int mes=fechaHoraActual.getMonthValue();
Modificar fechas/horas¶
Según la clase que manejemos tendremos una serie de métodos para añadir o quitar intervalos al dato
Método | Descripción |
---|---|
plusDays() / minusDays() | para sumar o restar días a la fecha |
plusWeeks() / minusWeeks() | para sumar o restar semanas |
plusMonths() / minusMonths() | para sumar o restar meses |
plusYears() / minusYears() | para sumar o restar años |
System.out.println("La fecha dentro de 10 días: " + LocalDate.now().plusDays(10) );
System.out.println("La fecha dentro de 2 semanas: " + LocalDate.now().plusWeeks(2) );
System.out.println("La fecha y hora de hace 32 horas: " + LocalDateTime.now().minusHours(32) );
Ajustadores temporales¶
Tenemos una clase muy útil TemporalAdjusters
que permite obtener nuevas fechas con ajustes muy utilizados
LocalDate fechaActual = LocalDate.now();
LocalDate ultimoDiaMesActual = fechaActual.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Último día del mes actual: " + ultimoDiaMesActual);
LocalDate primerDiaAnioSiguiente = fechaActual.with(TemporalAdjusters.firstDayOfNextYear());
System.out.println("Primer día del año siguiente: " + primerDiaAnioSiguiente);
Tiempo transcurrido entre fechas y horas¶
Otra tarea habitual que necesitaremos hacer es obtener la diferencia entre dos fechas u horas, o sea, el tiempo transcurrido entre dos instantes de tiempo.
Por ejemplo, imaginemos que queremos saber cuánto tiempo ha transcurrido entre la fecha de tu nacimiento y el día de hoy. Para averiguarlo sólo hay que hacer algo como esto:
LocalDate fNacimiento = LocalDate.of(1982, Month.MAY, 23);
System.out.println("Tu edad es de " +
ChronoUnit.YEARS.between(fNacimiento, LocalDate.now())
+ " años."
);
Otros ejemplos
LocalDateTime fechaInicio = LocalDateTime.of(2024, 4, 1, 8, 0); // 1 de abril de 2024, 08:00
LocalDateTime fechaFin = LocalDateTime.of(2024, 4, 10, 16, 30); // 10 de abril de 2024, 16:30
long diasEntre = ChronoUnit.DAYS.between(fechaInicio, fechaFin);
long horasEntre = ChronoUnit.HOURS.between(fechaInicio, fechaFin);
System.out.println("Días entre las fechas: " + diasEntre);
System.out.println("Horas entre las fechas: " + horasEntre);
Period
para medir períodos de tiempo entre fechas
LocalDate fechaInicio = LocalDate.of(2023, 12, 25); // 25 de diciembre de 2023
LocalDate fechaFin = LocalDate.of(2024, 1, 7); // 7 de enero de 2024
Period periodo = Period.between(fechaInicio, fechaFin);
int anios = periodo.getYears();
int meses = periodo.getMonths();
int dias = periodo.getDays();
System.out.println("Años: " + anios + ", Meses: " + meses + ", Días: " + dias);
Parseo de fechas¶
Para interpretar una fecha desde una cadena tenemos el método parse()
que si el formato cumple la ISO 8601 no hay que indicarle nada, en otro caso hay que utilizar la clase DateTimeFormatter
LocalDate fecha1 = LocalDate.parse("2020-07-06");
LocalDate fecha2 = LocalDate.parse("6/11/2020", DateTimeFormatter.ofPattern("d/M/yyyy") );
Formato personalizado de fechas¶
Al igual que podemos leer una fecha en el formato que necesitemos, podemos mostrar la fecha en el formato que queramos
Por defecto se muestra con el formato ISO 8601, podemos cambiar este formato como sigue
LocalDateTime fechaConHora = LocalDateTime.now();
DateTimeFormatter esDateFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm:ss");
System.out.println("Formato español (manual): " + fechaConHora.format(esDateFormat));
DateTimeFormatter
Podemos definir un formato específico para un idioma concreto mediate Locale
Teniendo en cuenta que por ejemplo, supongamos que queremos que el mes se muestre con su nombre completo y no con un número; para ello usaríamos el formato "MMMM" (las 4 M representan el nombre del mes). Por defecto ese nombre se mostraría en inglés, por lo que veríamos por pantalla, por ejemplo "July" y no "Julio", en español
DateTimeFormatter esDateFormatLargo =
DateTimeFormatter
.ofPattern("EEEE, dd 'de' MMMM 'de' yyyy 'a las' hh:mm:ss")
.withLocale(new Locale("es", "ES"));
System.out.println("Formato español (largo, localizado): " + fechaConHora.format(esDateFormatLargo));
//Formato español (largo, localizado): jueves, 11 de abril de 2024 a las 01:52:55
Pero puede ser necesario que la aplicación sea global y queramos que se muestre en el formato configurado en el sistema operativo donde se ejecuta
LocalDateTime fechaHoraActual = LocalDateTime.now();
// Obtener el formato del sistema operativo actual
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
// Formatear la fecha y hora actual según el formato del sistema operativo
String fechaFormateada = fechaHoraActual.format(formatter);
// Mostrar la fecha y hora formateada
System.out.println("Fecha y hora formateadas según el formato del sistema operativo actual: "
+ fechaFormateada);
//Fecha y hora formateadas según el formato del sistema operativo actual: 11 abr 2024 13:52:55