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?
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.
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)
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:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
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);
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());
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
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 );
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...
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!
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();
}
Le moyen le plus rapide pour LocalDateTime
-> Date
est:
Date.from(ldt.toInstant(ZoneOffset.UTC))
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+