¿Cuál es la mejor manera de convertir un java.util.Dateobjeto al nuevo JDK 8 / JSR-310 java.time.LocalDate?
Date input = new Date();
LocalDate date = ???
¿Cuál es la mejor manera de convertir un java.util.Dateobjeto al nuevo JDK 8 / JSR-310 java.time.LocalDate?
Date input = new Date();
LocalDate date = ???
Respuestas:
Respuesta corta
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Explicación
A pesar de su nombre, java.util.Daterepresenta un instante en la línea de tiempo, no una "fecha". Los datos reales almacenados dentro del objeto son un longrecuento de milisegundos desde 1970-01-01T00: 00Z (medianoche al comienzo de 1970 GMT / UTC).
La clase equivalente a java.util.Dateen 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.Dateinstancia no tiene concepto de zona horaria. Esto puede parecer extraño si llama toString()a un java.util.Date, porque toStringes 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 Instanttampoco contiene ninguna información sobre la zona horaria. Por lo tanto, para convertir de una Instanta 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 ZonedDateTimecontiene 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.
Dateno tiene concepto de zona horaria, Instanttampoco contiene información sobre la zona horaria. La LocalDateAPI dice "Una fecha sin zona horaria". Entonces, ¿por conversión de Datea Instanta LocalDatelas necesidades atZone(ZoneId.systemDefault())?
LocalDatey LocalDateTimeno "almacene ni represente una hora o zona horaria" (ref: javadocs). Si bien no lo almacenan, las clases representan una Localfecha y / o hora, por lo tanto, la conversión a fecha / hora local implica una zona horaria.
La mejor manera es:
Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()
Ventajas de esta versión:
funciona independientemente de que la entrada sea una instancia java.util.Dateo sea una subclase de java.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):
/**
* Utilities for conversion between the old and new JDK date types
* (between {@code java.util.Date} and {@code java.time.*}).
*
* <p>
* All methods are null-safe.
*/
public class DateConvertUtils {
/**
* Calls {@link #asLocalDate(Date, ZoneId)} with the system default time zone.
*/
public static LocalDate asLocalDate(java.util.Date date) {
return asLocalDate(date, ZoneId.systemDefault());
}
/**
* Creates {@link LocalDate} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static LocalDate asLocalDate(java.util.Date date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Date)
return ((java.sql.Date) date).toLocalDate();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDate();
}
/**
* Calls {@link #asLocalDateTime(Date, ZoneId)} with the system default time zone.
*/
public static LocalDateTime asLocalDateTime(java.util.Date date) {
return asLocalDateTime(date, ZoneId.systemDefault());
}
/**
* Creates {@link LocalDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static LocalDateTime asLocalDateTime(java.util.Date date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Timestamp)
return ((java.sql.Timestamp) date).toLocalDateTime();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDateTime();
}
/**
* Calls {@link #asUtilDate(Object, ZoneId)} with the system default time zone.
*/
public static java.util.Date asUtilDate(Object date) {
return asUtilDate(date, ZoneId.systemDefault());
}
/**
* Creates a {@link java.util.Date} from various date objects. Is null-safe. Currently supports:<ul>
* <li>{@link java.util.Date}
* <li>{@link java.sql.Date}
* <li>{@link java.sql.Timestamp}
* <li>{@link java.time.LocalDate}
* <li>{@link java.time.LocalDateTime}
* <li>{@link java.time.ZonedDateTime}
* <li>{@link java.time.Instant}
* </ul>
*
* @param zone Time zone, used only if the input object is LocalDate or LocalDateTime.
*
* @return {@link java.util.Date} (exactly this class, not a subclass, such as java.sql.Date)
*/
public static java.util.Date asUtilDate(Object date, ZoneId zone) {
if (date == null)
return null;
if (date instanceof java.sql.Date || date instanceof java.sql.Timestamp)
return new java.util.Date(((java.util.Date) date).getTime());
if (date instanceof java.util.Date)
return (java.util.Date) date;
if (date instanceof LocalDate)
return java.util.Date.from(((LocalDate) date).atStartOfDay(zone).toInstant());
if (date instanceof LocalDateTime)
return java.util.Date.from(((LocalDateTime) date).atZone(zone).toInstant());
if (date instanceof ZonedDateTime)
return java.util.Date.from(((ZonedDateTime) date).toInstant());
if (date instanceof Instant)
return java.util.Date.from((Instant) date);
throw new UnsupportedOperationException("Don't know hot to convert " + date.getClass().getName() + " to java.util.Date");
}
/**
* Creates an {@link Instant} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static Instant asInstant(Date date) {
if (date == null)
return null;
else
return Instant.ofEpochMilli(date.getTime());
}
/**
* Calls {@link #asZonedDateTime(Date, ZoneId)} with the system default time zone.
*/
public static ZonedDateTime asZonedDateTime(Date date) {
return asZonedDateTime(date, ZoneId.systemDefault());
}
/**
* Creates {@link ZonedDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/
public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) {
if (date == null)
return null;
else
return asInstant(date).atZone(zone);
}
}
El asLocalDate()método aquí es nulo-seguro, utiliza toLocalDate(), si la entrada es java.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.
DateConvertUtils.
Date.toInstant().
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );
SimpleDateFormatinstancia se limita al hilo actual. Se utiliza de forma segura para subprocesos. Ahora, SimpleDateFormattiene 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. (Una ThreadLocalsolución puede funcionar si el código 'contaminante' Threaden esto es responsable del ciclo de vida del hilo ... pero eso rara vez sucede). Torpe. Evitar SimpleDateFormates la razón para usar javax.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:
Date input = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(input);
LocalDate date = LocalDate.of(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH));
LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();
Puedes convertir en una línea:
public static LocalDate getLocalDateFromDate(Date date){
return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}
primero, es fácil convertir una fecha en un instante
Instant timestamp = new Date().toInstant();
Luego, puede convertir el Instant a cualquier api de fecha en jdk 8 usando el método ofInstant ():
LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault());
import java.sql.Dateen su archivo: el toInstant()método de java.sql.Datesiempre tira.
Date input = new Date();
LocalDateTime conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();
La Dateinstancia también contiene tiempo junto con la fecha, mientras LocalDateque no. Por lo tanto, primero puede convertirlo LocalDateTimeusando su método, ofInstant()luego, si lo desea sin tiempo , convierta la instancia en LocalDate.
public static LocalDate Date2LocalDate(Date date) {
return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))
este formato es de Date#tostring
public String toString() {
// "EEE MMM dd HH:mm:ss zzz yyyy";
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
if (index == BaseCalendar.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
sb.append(' ').append(date.getYear()); // yyyy
return sb.toString();
}
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 .
Date input = new Date();
GregorianCalendar gregorianCalendar = (GregorianCalendar) Calendar.getInstance();
gregorianCalendar.setTime(input);
ZonedDateTime zonedDateTime = gregorianCalendar.toZonedDateTime();
zonedDateTime.toLocalDate();
¿Qué hay de malo en esta 1 línea simple?
new LocalDateTime(new Date().getTime()).toLocalDate();
Resolví esta pregunta con la solución a continuación
import org.joda.time.LocalDate;
Date myDate = new Date();
LocalDate localDate = LocalDate.fromDateFields(myDate);
System.out.println("My date using Date" Nov 18 11:23:33 BRST 2016);
System.out.println("My date using joda.time LocalTime" 2016-11-18);
En este caso, localDate imprime su fecha en este formato "aaaa-MM-dd"
java.timeclases en JDK8, no con Joda Time.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))Creo que es equivalente a la suya, pero más directa.