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

Java 8 dispose d’une toute nouvelle API pour la date et l’heure. Une des classes les plus utiles de cette API est LocalDateTime , pour conserver 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 avec l’ancien et le nouveau code, il faudra procéder à une conversion entre les deux. Comme il ne semble pas y avoir de méthodes directes pour y parvenir, comment peut-on le faire?

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 sur 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’object représentent un nombre important de millisecondes depuis 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 fournir la conversion aller et retour:

 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 toSsortingng() sur un java.util.Date , car le toSsortingng est relatif à un fuseau horaire. Cependant, cette méthode utilise en fait le fuseau horaire par défaut de Java pour fournir la chaîne. Le fuseau horaire ne fait pas partie de l’état réel de java.util.Date .

Un Instant ne contient pas non plus d’informations sur le fuseau horaire. Ainsi, pour convertir un Instant en Instant en une date-heure locale, il est nécessaire de spécifier un fuseau horaire. Cela peut être la zone par défaut – ZoneId.systemDefault() – ou il peut s’agir d’un fuseau horaire que votre application contrôle, tel qu’un fuseau horaire à partir des préférences de l’utilisateur. LocalDateTime a une méthode de fabrique pratique qui prend à la fois l’instant et le fuseau horaire:

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

En sens inverse, le LocalDateTime le fuseau horaire est spécifié en appelant la atZone(ZoneId) . Le ZonedDateTime peut ensuite être converti directement en Instant :

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

Notez que la conversion de LocalDateTime à ZonedDateTime peut ZonedDateTime 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 heure de date locale se produit deux fois. Au spring, il y a un vide, où une heure disparaît. Voir le Javadoc de atZone(ZoneId) pour plus de définition de ce que fera la conversion.

Récapitulatif, si vous arrondissez un java.util.Date à un LocalDateTime et retournez à un java.util.Date vous pouvez vous retrouver avec un instant différent en raison de l’heure d’été.

Informations complémentaires: Il existe une autre différence qui affectera les très anciennes dates. java.util.Date utilise un calendrier qui a des chances au 15 octobre 1582, avec des dates antérieures à celle du calendrier julien au lieu du calendrier grégorien. En revanche, java.time.* Utilise le système de calendrier ISO (équivalent au grégorien) pour tous les temps. Dans la plupart des cas d’utilisation, le système de calendrier ISO est ce que vous voulez, mais vous pouvez voir des effets étranges lorsque vous comparez les dates avant l’année 1582.

Voici ce que je suis venu avec (et comme toutes les énigmes Date Time, il va probablement être réfuté sur la base d’un ajustement bizarre du fuseau horaire-année: D)

LocalDateTime : 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éer un Instant partir de la Date :

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

Créer une Date partir d’ 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 d’ Instant

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

(2) Date << Instant << LocalDateTime

Créez Instant from LocalDateTime :

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

Créer une Date partir d’ Instant :

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

La sortie est la suivante:

 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 

Beaucoup plus pratique si vous êtes sûr d’avoir besoin d’un fuseau horaire par défaut:

 Date d = java.sql.Timestamp.valueOf( myLocalDateTime ); 

les éléments suivants semblent fonctionner lors de la conversion de la nouvelle API LocalDateTime en 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 façon …

J’espère que cela aide…

Je ne suis pas sûr si c’est le moyen le plus simple ou le meilleur, ou s’il y a des pièges, mais ça marche:

 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(); } 

Tout est ici: http://blog.progs.be/542/date-to-java-time

La réponse avec “round-sortingpping” n’est pas exacte: quand vous le faites

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

Si le fuseau horaire de votre système n’est pas UTC / GMT, vous modifiez l’heure!