web-dev-qa-db-fra.com

Comment convertir LocalDateTime en date en Java 8

J'utilise le fuseau horaire du Brésil par défaut, mais lorsqu'il est pris un LocalDateTime de New York et converti en Java.tim.Instant le instant est rempli correctement. Le problème est quand j'essaie de générer un Date avec Date.from (instantValue), au lieu d'être généré un date de New York, je finissent par obtenir la date actuelle du Brésil.

ZoneId nyZone = ZoneId.of("America/New_York");
ZoneId brazilZone = ZoneId.of("America/Recife");

LocalDateTime ldtBrazil = LocalDateTime.now(brazilZone);
LocalDateTime ldtNY = LocalDateTime.now(nyZone);

Instant instantBrazil = ldtBrazil.toInstant(ZoneOffset.UTC);
Instant instantNY = ldtNY.toInstant(ZoneOffset.UTC);

System.out.println("-------LocalDateTime-------");
System.out.println("ldtBrazil    : "+ldtBrazil);
System.out.println("ldtNY        : "+ldtNY);

System.out.println("\n-------Instant-------");
System.out.println("instantBrazil: "+instantBrazil);
System.out.println("instantNY    : "+instantNY);

long milliBrazil = instantBrazil.toEpochMilli();
long milliNY = instantNY.toEpochMilli();

System.out.println("\n----------Milli----------");
System.out.println("miliBrazil : "+milliBrazil);
System.out.println("miliNY     : "+milliNY);

Date dateBrazil = Date.from(instantBrazil);
Date dateNY = Date.from(instantNY);

System.out.println("\n---------Date From Instant---------");
System.out.println("dateBrazil: "+dateBrazil);
System.out.println("dateNY    : "+dateNY);

System.out.println("\n---------Date From Milli---------");
System.out.println("dateBrazil: "+new Date(milliBrazil));
System.out.println("dateNY    : "+new Date(milliNY));

Résultat

-------LocalDateTime-------
ldtBrazil    : 2016-09-21T22:11:52.118
ldtNY        : 2016-09-21T21:11:52.118

-------Instant-------
instantBrazil: 2016-09-21T22:11:52.118Z
instantNY    : 2016-09-21T21:11:52.118Z

----------Milli----------
miliBrazil : 1474495912118
miliNY     : 1474492312118

---------Date From Instant---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016 //this data must be related to   NY LocalDateTime, but reiceved a same date of Brazil.

---------Date From Milli---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016
10
André Henriques

LocalDateTime signifie pas de zone

Vous semblez mal comprendre le but de LocalDateTime .

Cette classe n'a ni fuseau horaire ni offset-from-UTC . C'est pas un point sur la timeline. Il représente plutôt une vague idée des moments possibles. Le nom "Local…" peut être contre-intuitif car il représente pas représente une localité particulière, mais plutôt n'importe localité.

Par exemple, Noël cette année est minuit au début du 25 décembre 2016 ou 2016-12-25T00:00. Cela n'a aucun sens jusqu'à ce que vous appliquiez un fuseau horaire pour obtenir Noël à Auckland NZ ou Kolkata IN ou Paris FR ou Montréal CA, chacun étant un point différent sur la chronologie, devenant de plus en plus tard en allant vers l'ouest.

N'utilisez jamais LocalDateTime car vous pensez que cela vous évitera les tracas des zones et des décalages. Au contraire, vous vous creuserez dans un trou avec des valeurs de date-heure ambiguës.

Focus sur UTC

La plupart de votre logique métier, de la journalisation, du stockage et de l'échange de données doivent tous être dans UTC . Pensez à l'UTC comme la seule vraie heure; toutes les autres zones et décalages se font passer pour des valeurs UTC habillées.

Dans Java.time, cela signifie que la classe Instant est votre classe de référence, les blocs de construction de base des objets date-heure. La classe Instant représente un moment de la chronologie dans UTC avec une résolution de nanosecondes .

Instant now = Instant.now();

ZonedDateTime

Ajustez les fuseaux horaires uniquement lorsque cela est nécessaire pour accéder à heure de l'horloge murale d'une région. Appliquez un ZoneId pour obtenir un objet ZonedDateTime.

ZoneId zNewYork = ZoneId.of("America/New_York");
ZoneId zRecife = ZoneId.of("America/Recife");

ZonedDateTime zdtNewYork = now.atZone( zNewYork );
ZonedDateTime zdtRecife = now.atZone( zRecife );

Ces trois objets, now, zdtNewYork et zdtRecife, sont à tout moment , le même point simultané sur la timeline. Tous les trois partagent le même décompte de l'époque. La seule différence est l'objectif à travers lequel on voit leur horloge murale.

Évitez les anciennes classes de date et d'heure

Évitez d'utiliser les anciennes classes de date et heure gênantes fournies avec les premières versions de Java. Alors, évitez Java.util.Date et Java.util.Calendar. Ils sont vraiment si mauvais. Restez avec les classes Java.time.

Si vous devez interagir avec un ancien code non encore mis à jour pour les types Java.time, vous pouvez convertir vers/depuis les types Java.time. Recherchez de nouvelles méthodes ajoutées aux anciennes classes. Le Java.util.Date.from la méthode prend un Instant. Nous pouvons extraire un Instant d'un ZoneDateTime (ou de OffsetDateTime).

Java.util.Date utilDate = Java.util.Date.from( zdtNewYork.toInstant() );

Et aller dans l'autre sens.

Instant instant = utilDate.toInstant();

Pour plus d'informations sur la conversion, voir ma réponse à la question, Convertir Java.util.Date en quel type "Java.time"?

Évitez le comptage de l'époque

Évitez d'utiliser les nombres de comptage à partir de l'époque tels que millisecondes depuis le début de 1970 en UTC. Il existe différentes granularités utilisées pour le comptage (millisecondes, microsecondes, nanosecondes, secondes entières, etc.). Il y a au moins une douzaine d'époques utilisées par divers systèmes informatiques en plus de 1970. Les chiffres n'ont aucune signification lorsqu'ils sont lus par les humains, donc les bogues peuvent passer inaperçus.

Vous pourriez les trouver utiles lors de la pratique. Appelez getEpochSecond et getNano sur Instant, ou pour une valeur tronquée, appelez toEpochMilli.


À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent l'ancien hérité) gênant classes date-heure telles que Java.util.Date , Calendar , & SimpleDateFormat .

Le projet Joda-Time , maintenant en mode maintenance , conseille la migration vers les classes Java.time .

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 31 .

Vous pouvez échanger des objets Java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de Java.sql.* Des classes.

Où obtenir les classes Java.time?

Le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à Java.time. Vous pouvez trouver ici des classes utiles telles que Interval , YearWeek , YearQuarter , et plus .

20
Basil Bourque

Il me semble que vous êtes confus quant à la différence entre un LocalDateTime et un Instant (ou un Date, ce qui est essentiellement la même chose qu'un Instant). Ce sont des objets complètement différents.

Un LocalDateTime est une date de calendrier et une heure d'horloge particulières. Vous pouvez le penser comme cette image.

LocalDateTime

Ou vous pouvez le considérer comme une année, un mois, un jour, une heure, une minute et une seconde. Mais il n'a pas de fuseau horaire. C'est juste ce que dit le calendrier et ce que dit l'horloge.

Un Instant est un moment dans le temps. Par exemple, le moment où Neil Armstrong a marché pour la première fois sur la lune pourrait être représenté par un Instant. Tout comme le moment où JFK a été abattu.

Encore une fois, il n'y a pas de fuseau horaire. Mais c'est quelque chose de différent d'un LocalDateTime. Vous ne pouvez pas noter l'heure à laquelle un Instant est sauf si vous savez pour quel fuseau horaire pour l'écrire. Oh, et un Date est la même chose qu'un Instant.

Par conséquent, pour convertir entre un LocalDateTime et un Instant, vous devez référencer un fuseau horaire particulier. Donc, pour exprimer le moment où Neil Armstrong a marché sur la lune comme une année, un mois, une date, une heure, une minute et une seconde; vous devez savoir quel fuseau horaire utiliser. Si vous utilisez UTC, il était 2 h 56 le 21 juillet 1969. Si vous utilisez l'heure normale du Pacifique, il était 18 h 56 le 20 juillet 1969.

Armés de ces connaissances, analysons votre code. Vous avez commencé avec quelques objets LocalDateTime.

  • ldtBrazil est l'heure actuelle au Brésil - 22:11:52 le 21 septembre.
  • ldtNY est l'heure actuelle à New York - 21:11:52 le 21 septembre.

Maintenant, vous utilisez UTC pour les convertir en objets Instant.

  • instantBrazil est le moment où il était 22:11:52 à Tombouctou (qui utilise UTC toute l'année).
  • instantNY est le moment où il était 21:11:52 à Tombouctou (une heure plus tôt qu'instantBrazil).

Ensuite, vous les imprimez. Nous devons connaître un fuseau horaire pour pouvoir le faire, mais ça va. Un Instant est imprimé en UTC, quoi qu'il arrive. C'est ce que signifie le Z.

Maintenant, vous convertissez les objets Instant en un nombre de millisecondes. Bien. Il s'agit du nombre de millisecondes écoulées depuis minuit le 1er janvier 1970, UTC. milliNY est évidemment 3,6 millions de moins que milliBrazil, car cela correspond à un Instant qui est une heure plus tôt.

Ensuite, vous convertissez les objets Instant en objets Date. Cela ne change rien, car un Date et un Instant représentent la même chose, même s'ils sont imprimés différemment.

Vous imprimez ces objets Date convertis. Ils sont imprimés en heure brésilienne, car c'est votre région. Et il se trouve que dateNY est une heure plus tôt que dateBrazil; mais ils sont tous les deux imprimés en heure brésilienne, soit trois heures de retard sur UTC. Vous obtenez donc 19:11:52 et 18:11:52 respectivement.

Enfin, vous créez quelques autres Date objets, à partir du nombre de millisecondes. Mais ces nouveaux objets Date sont exactement égaux aux dateBrazil et dateNY que vous avez déjà, puisque vous les avez créés à partir du même nombre de millisecondes. Et encore une fois, ils sont imprimés en heure brésilienne.

6
Dawood ibn Kareem