web-dev-qa-db-fra.com

Convertir Java.util.Date en Java.time.LocalDate

Quel est le meilleur moyen de convertir un objet Java.util.Date dans le nouveau JDK 8/JSR-310 Java.time.LocalDate?

Date input = new Date();
LocalDate date = ???
411
JodaStephen

Réponse courte

Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

Explication

Malgré son nom, Java.util.Date représente un instant sur la ligne de temps, pas une "date". Les données réelles stockées dans l'objet sont un nombre long de millisecondes depuis le 1970-01-01T00: 00Z (à minuit au début de 1970 GMT/UTC).

La classe équivalente à Java.util.Date dans JSR-310 est Instant; il existe donc une méthode pratique toInstant() pour fournir la conversion:

Date input = new Date();
Instant instant = input.toInstant();

Une instance Java.util.Date n'a pas de concept de fuseau horaire. Cela peut sembler étrange si vous appelez toString() sur un Java.util.Date, car toString est relatif à un fuseau horaire. Cependant, cette méthode utilise réellement le fuseau horaire par défaut de Java pour fournir la chaîne. Le fuseau horaire ne fait pas partie de l'état actuel de Java.util.Date.

Un Instant ne contient pas non plus d'informations sur le fuseau horaire. Ainsi, pour convertir un Instant en une date locale, il est nécessaire de spécifier un fuseau horaire. Il peut s'agir de la zone par défaut - ZoneId.systemDefault() - ou d'un fuseau horaire contrôlé par votre application, tel qu'un fuseau horaire à partir des préférences de l'utilisateur. Utilisez la méthode atZone() pour appliquer le fuseau horaire:

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());

Un ZonedDateTime contient un état composé de la date et de l'heure locales, du fuseau horaire et du décalage par rapport à GMT/UTC. En tant que tel, la date - LocalDate - peut être facilement extraite à l'aide de toLocalDate():

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();

Réponse de Java 9

Dans Java SE 9, une nouvelle méthode a été ajoutée pour simplifier légèrement cette tâche:

Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());

Cette nouvelle alternative est plus directe, crée moins de déchets et devrait donc donner de meilleurs résultats.

715
JodaStephen

Une meilleure façon est:

Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()

Avantages de cette version:

  • fonctionne indépendamment du fait que l'entrée soit une instance de Java.util.Date ou sa sous-classe Java.sql.Date (contrairement à la manière de @ JodaStephen). Ceci est commun aux données provenant de JDBC. Java.sql.Date.toInstant() lève toujours une exception.

  • il en va de même pour JDK8 et JDK7 avec backport JSR-310

Personnellement, j'utilise une classe utilitaire (mais ce n'est pas compatible avec le 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);
    }

}

La méthode asLocalDate() ici est null-safe, utilise toLocalDate(), si l'entrée est Java.sql.Date (elle peut être remplacée par le pilote JDBC pour éviter les problèmes de fuseau horaire ou les calculs inutiles), sinon utilise la méthode susmentionnée.

139
Oliv

Si vous utilisez Java 8, la réponse de @ JodaStephen est évidemment la meilleure. Toutefois, si vous travaillez avec le backport JSR-310 , vous devez malheureusement procéder de la manière suivante:

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));
17
dhalsim2
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );
15
ceklock
LocalDate ld = new Java.sql.Date( new Java.util.Date().getTime() ).toLocalDate();
13
Gustavo

Vous pouvez convertir en une seule ligne:

public static LocalDate getLocalDateFromDate(Date date){
   return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}
7
Sahil Chhabra

d'abord, il est facile de convertir une date en un instant

Instant timestamp = new Date().toInstant(); 

Ensuite, vous pouvez convertir l’instant Instant en n’importe quelle API de date dans jdk 8 à l’aide de la méthode ofInstant ():

LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault()); 
6
Shedom Wei
public static LocalDate Date2LocalDate(Date date) {
        return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))

ce format est 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();
    }
1
宏杰李

Quel est le problème avec cette ligne 1 simple?

new LocalDateTime(new Date().getTime()).toLocalDate();
0
Lawrence

J'ai eu des problèmes avec l'implémentation de @ JodaStephen sur JBoss EAP 6. J'ai donc réécrit la conversion suivant le didacticiel Java d'Oracle dans 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();
0
rogerio_gentil
Date input = new Date();
LocalDateTime  conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();

L'instance Date contient aussi l'heure avec la date, alors que LocalDate n'en contient pas. Donc, vous pouvez d’abord le convertir en LocalDateTime en utilisant sa méthode ofInstant(), puis si vous le voulez sans time puis convertir l’instance en LocalDate.

0
Arun Raaj