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
LocalDateTime
signifie pas de zoneVous 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.
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 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 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
.
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 .
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.
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
.
Maintenant, vous utilisez UTC pour les convertir en objets Instant
.
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.