web-dev-qa-db-fra.com

Conversion entre Java.time.LocalDateTime et Java.util.Date

Java 8 dispose d'une toute nouvelle API pour la date et l'heure. L'une des classes les plus utiles de cette API est LocalDateTime, pour la conservation d'une valeur date-heure indépendante du fuseau horaire.

Il existe probablement des millions de lignes de code utilisant la classe héritée Java.util.Date à cette fin. En tant que tel, lors de l'interfaçage de l'ancien et du nouveau code, une conversion entre les deux sera nécessaire. Comme il semble n'y avoir aucune méthode directe pour accomplir cela, comment peut-on le faire?

443
Knut Arne Vedaa

Réponse courte:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

Explication: (basé sur cette question à propos de LocalDate)

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 des méthodes pratiques pour effectuer la conversion:

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

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 la toString est relative à 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 d'un Instant à une date-heure locale, il est nécessaire de spécifier un fuseau horaire. Il peut s'agir du fuseau horaire par défaut - ZoneId.systemDefault() - ou du fuseau horaire que votre application contrôle, tel qu'un fuseau horaire défini dans les préférences de l'utilisateur. LocalDateTime a une méthode d'usine pratique qui prend à la fois l'instant et le fuseau horaire:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

À l'inverse, la LocalDateTime du fuseau horaire est spécifiée en appelant la méthode atZone(ZoneId). La ZonedDateTime peut ensuite être convertie directement en Instant:

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

Notez que la conversion de LocalDateTime en ZonedDateTime peut entraîner un comportement inattendu. Cela est dû au fait que toutes les dates et heures locales n'existent pas en raison de l'heure d'été. En automne/automne, il y a un chevauchement dans la ligne de temps locale où la même date-heure locale se produit deux fois. Au printemps, il y a un intervalle, où une heure disparaît. Voir la Javadoc de atZone(ZoneId) pour en savoir plus sur ce que la conversion fera.

En résumé, si vous alliez un Java.util.Date à un LocalDateTime et revenez à un Java.util.Date, vous risquez de vous retrouver avec un autre instant en raison de l'heure d'été.

Informations complémentaires: Il existe une autre différence qui affectera les dates très anciennes. Java.util.Date utilise un calendrier qui change le 15 octobre 1582, les dates antérieures utilisant le calendrier Julien au lieu de celui de Grégorien. En revanche, Java.time.* utilise le système de calendrier ISO (équivalent du grégorien) à tout moment. Dans la plupart des cas d'utilisation, le système de calendrier ISO est ce que vous voulez, mais vous pouvez constater des effets étranges lorsque vous comparez des dates antérieures à 1582.

666
JodaStephen

Voici ce que j’ai trouvé (et comme toutes les énigmes Date Time, il va probablement être réfuté en fonction d’un étrange réglage du fuseau horaire, de l’année-jour et de la lumière du jour: D)

Aller-retour: Date << - >> LocalDateTime

Étant donné: 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);

Exemple:

Donné:

Date date = new Date();
System.out.println(date + " long: " + date.getTime());

(1) LocalDateTime << Instant << Date:

Crée Instant à partir de Date:

Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);

Crée Date à partir de Instant (pas nécessaire, mais à titre d'illustration):

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

Créer LocalDateTime à partir de Instant

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);

(2) Date << Instant << LocalDateTime

Créer Instant à partir de LocalDateTime:

instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);

Créer Date à partir de Instant:

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

La sortie est:

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
126
The Coordinator

Un moyen bien plus pratique si vous êtes sûr d'avoir besoin d'un fuseau horaire par défaut:

Date d = Java.sql.Timestamp.valueOf( myLocalDateTime );
19
Petrychenko

les éléments suivants semblent fonctionner lors de la conversion de la nouvelle API LocalDateTime vers Java.util.date:

Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());

la conversion inverse peut être (espérons-le) réalisée de la même manière ...

j'espère que ça aide...

7
dizzy

Tout est là: http://blog.progs.be/542/date-to-Java-time

La réponse avec "aller-retour" n'est pas exacte: quand vous faites

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

si le fuseau horaire de votre système n'est pas UTC/GMT, vous changez l'heure!

3
joe-mojo

Je ne sais pas si c'est le moyen le plus simple ou le meilleur, ou s'il y a des pièges, mais cela fonctionne:

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();
}
3
Knut Arne Vedaa

Le moyen le plus rapide pour LocalDateTime -> Date est:

Date.from(ldt.toInstant(ZoneOffset.UTC))

2
Lukasz Czerwinski

Si vous êtes sur Android et que vous utilisez threetenbp , vous pouvez utiliser DateTimeUtils à la place.

ex:

Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

vous ne pouvez pas utiliser Date.from car il n'est supporté que par api 26+

2
humazed