¿Cuál es la mejor manera de convertir un java.util.Date
objeto al nuevo JDK 8 / JSR-310 java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Respuesta corta
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Explicación
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 son un long
recuento 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, hay un método conveniente toInstant()
para proporcionar la conversión:
Date input = new Date();
Instant instant = input.toInstant();
Una java.util.Date
instancia no tiene concepto de zona horaria. Esto puede parecer extraño si llama toString()
a un java.util.Date
, porque toString
es relativo a una zona horaria. Sin embargo, ese método en realidad usa la zona horaria predeterminada de Java sobre la marcha para proporcionar la cadena. La zona horaria no es parte del estado real de java.util.Date
.
An Instant
tampoco contiene ninguna información sobre la zona horaria. Por lo tanto, para convertir de una Instant
a una fecha local, es necesario especificar una zona horaria. Esta podría ser la zona predeterminada ZoneId.systemDefault()
, o podría ser una zona horaria que controla su aplicación, como una zona horaria de las preferencias del usuario. Use el atZone()
método para aplicar la zona horaria:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
A ZonedDateTime
contiene un estado que consiste en la fecha y hora local, la zona horaria y el desplazamiento de GMT / UTC. Como tal, la fecha - LocalDate
- se puede extraer fácilmente usando toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Respuesta de Java 9
En Java SE 9, se ha agregado un nuevo método que simplifica ligeramente esta tarea:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Esta nueva alternativa es más directa, crea menos basura y, por lo tanto, debería funcionar mejor.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
Creo que es equivalente a la suya, pero más directa.Date
no tiene concepto de zona horaria,Instant
tampoco contiene información sobre la zona horaria. LaLocalDate
API dice "Una fecha sin zona horaria". Entonces, ¿por conversión deDate
aInstant
aLocalDate
las necesidadesatZone(ZoneId.systemDefault())
?LocalDate
yLocalDateTime
no "almacene ni represente una hora o zona horaria" (ref: javadocs). Si bien no lo almacenan, las clases representan unaLocal
fecha y / o hora, por lo tanto, la conversión a fecha / hora local implica una zona horaria.La mejor manera es:
Ventajas de esta versión:
funciona independientemente de que la entrada sea una instancia
java.util.Date
o sea una subclase dejava.sql.Date
(a diferencia de @ JodaStephen). Esto es común con los datos originados por JDBC.java.sql.Date.toInstant()
siempre arroja una excepción.es lo mismo para JDK8 y JDK7 con backport JSR-310
Yo personalmente uso una clase de utilidad (pero no es compatible con el backport):
El
asLocalDate()
método aquí es nulo-seguro, utilizatoLocalDate()
, si la entrada esjava.sql.Date
(puede ser anulada por el controlador JDBC para evitar problemas de zona horaria o cálculos innecesarios), de lo contrario utiliza el método mencionado anteriormente.fuente
DateConvertUtils
.Date.toInstant()
.fuente
SimpleDateFormat
instancia se limita al hilo actual. Se utiliza de forma segura para subprocesos. Ahora,SimpleDateFormat
tiene fama de ser 'caro para crear una instancia' (en la cuenta de todas las estructuras de datos internas que necesita) pero no se puede compartir una como 'Singleton' (sin sincronizar el acceso a ella), porque es de hecho no es thread- seguro. (UnaThreadLocal
solución puede funcionar si el código 'contaminante'Thread
en esto es responsable del ciclo de vida del hilo ... pero eso rara vez sucede). Torpe. EvitarSimpleDateFormat
es la razón para usarjavax.time
.SimpleDateFormat
(que se tira), la cadena intermedia (que se tira) y el costo del análisis. Es una solución, pero no se recomienda.Si está utilizando Java 8, la respuesta de @ JodaStephen es obviamente la mejor. Sin embargo, si está trabajando con el puerto JSR-310 , desafortunadamente tiene que hacer algo como esto:
fuente
fuente
Puedes convertir en una línea:
fuente
primero, es fácil convertir una fecha en un instante
Luego, puede convertir el Instant a cualquier api de fecha en jdk 8 usando el método ofInstant ():
fuente
import java.sql.Date
en su archivo: eltoInstant()
método dejava.sql.Date
siempre tira.La
Date
instancia también contiene tiempo junto con la fecha, mientrasLocalDate
que no. Por lo tanto, primero puede convertirloLocalDateTime
usando su método,ofInstant()
luego, si lo desea sin tiempo , convierta la instancia enLocalDate
.fuente
este formato es de
Date#tostring
fuente
He tenido problemas con la implementación de @ JodaStephen en JBoss EAP 6. Entonces, reescribí la conversión siguiendo el Tutorial Java de Oracle en http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .
fuente
¿Qué hay de malo en esta 1 línea simple?
fuente
Resolví esta pregunta con la solución a continuación
En este caso, localDate imprime su fecha en este formato "aaaa-MM-dd"
fuente
java.time
clases en JDK8, no con Joda Time.