manejo - restar fechas en java 8
Conversión entre java.time.LocalDateTime y java.util.Date (7)
Java 8 tiene una API completamente nueva para fecha y hora. Una de las clases más útiles en esta API es LocalDateTime
, para mantener un valor de fecha y hora independiente de la zona horaria.
Probablemente hay millones de líneas de código utilizando la clase heredada java.util.Date
para este propósito. Como tal, cuando se conecte el código antiguo con el nuevo, será necesario convertir entre los dos. Como parece que no hay métodos directos para lograr esto, ¿cómo puede hacerse?
Esto es lo que se me ocurrió (y, como en todos los enigmas de Date Time, probablemente será refutado en función de algún ajuste extraño en la zona horaria-leapyear-daylight daylight): D)
Round-tripping: Date
<<->> LocalDateTime
Dado: Date date = [some date]
(1) LocalDateTime
<< Instant
<< Date
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
(2) Date
<< Instant
<< LocalDateTime
Instant instant = ldt.toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
Ejemplo:
Dado:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
(1) LocalDateTime
<< Instant
<< Date
:
Crear Instant
desde la Date
:
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:/n" + instant);
Crear Date
desde Instant
(no es necesario, pero para ilustración):
date = Date.from(instant);
System.out.println("Date from Instant:/n" + date + " long: " + date.getTime());
Crear LocalDateTime
desde Instant
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:/n" + ldt);
(2) Date
<< Instant
<< LocalDateTime
Crear Instant
desde LocalDateTime
:
instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:/n" + instant);
Crear Date
desde el Instant
:
date = Date.from(instant);
System.out.println("Date from Instant:/n" + date + " long: " + date.getTime());
La salida es:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Instant from Date:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
LocalDateTime from Instant:
2013-11-01T14:13:04.574
Instant from LocalDateTime:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Lo siguiente parece funcionar cuando se convierte de la nueva API LocalDateTime a java.util.date:
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
la conversión inversa se puede (con suerte) lograr de manera similar ...
Espero eso ayude...
No estoy seguro de si esta es la forma más simple o mejor, o si hay alguna trampa, pero funciona:
static public LocalDateTime toLdt(Date date) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
ZonedDateTime zdt = cal.toZonedDateTime();
return zdt.toLocalDateTime();
}
static public Date fromLdt(LocalDateTime ldt) {
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
GregorianCalendar cal = GregorianCalendar.from(zdt);
return cal.getTime();
}
Respuesta corta:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Explicación: (basado en esta pregunta sobre LocalDate
)
A pesar de su nombre, java.util.Date
representa un instante en la línea de tiempo, no una "fecha". Los datos reales almacenados dentro del objeto es un conteo long
de milisegundos desde 1970-01-01T00: 00Z (medianoche al comienzo de 1970 GMT / UTC).
La clase equivalente a java.util.Date
en JSR-310 es Instant
, por lo tanto, existen métodos convenientes para proporcionar la conversión de un lado a otro:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
Una instancia java.util.Date
no tiene un concepto de zona horaria. Esto puede parecer extraño si llama a toString()
en un java.util.Date
, porque el toString
es relativo a una zona horaria. Sin embargo, ese método realmente utiliza la zona horaria predeterminada de Java sobre la marcha para proporcionar la cadena. La zona horaria no forma parte del estado real de java.util.Date
.
An Instant
tampoco contiene información sobre la zona horaria. Por lo tanto, para convertir una fecha Instant
a una hora local, es necesario especificar una zona horaria. Esta podría ser la zona predeterminada - ZoneId.systemDefault()
- o podría ser una zona horaria que controle su aplicación, como una zona horaria desde las preferencias del usuario. LocalDateTime
tiene un método de fábrica conveniente que toma tanto el instante como la zona horaria:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
A la inversa, LocalDateTime
la zona horaria se especifica llamando al atZone(ZoneId)
. El ZonedDateTime
se puede convertir directamente a un Instant
:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Tenga en cuenta que la conversión de LocalDateTime
a ZonedDateTime
tiene el potencial de introducir un comportamiento inesperado. Esto se debe a que no todas las fechas y horarios locales existen debido al horario de verano. En otoño / otoño, hay una superposición en la línea de tiempo local donde la misma fecha y hora local se produce dos veces. En primavera, hay un hueco, donde desaparece una hora. Consulte el Javadoc de atZone(ZoneId)
para obtener más información sobre lo que hará la conversión.
En resumen, si LocalDateTime
un java.util.Date
a un LocalDateTime
y vuelve a un java.util.Date
, puede terminar con un instante diferente debido al horario de verano.
Información adicional: Hay otra diferencia que afectará a fechas muy antiguas. java.util.Date
usa un calendario que aparece el 15 de octubre de 1582, con fechas anteriores al calendario juliano en lugar del calendario gregoriano. Por el contrario, java.time.*
Utiliza el sistema de calendario ISO (equivalente al gregoriano) para todos los tiempos. En la mayoría de los casos de uso, el sistema de calendario ISO es lo que desea, pero puede ver efectos extraños al comparar fechas anteriores al año 1582.
Si tienes Android y usas threetenbp puedes usar DateTimeUtils
lugar.
ex:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
no puedes usar Date.from
ya que solo es compatible con api 26+
Todo está aquí: http://blog.progs.be/542/date-to-java-time
La respuesta con "ida y vuelta" no es exacta: cuando lo haces
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
Si la zona horaria de su sistema no es UTC / GMT, ¡cambia la hora!
Una forma mucho más conveniente si está seguro de que necesita una zona horaria predeterminada:
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );