LocalDateTime à ZonedDateTime
Que je dispose de Java 8 Printemps application web qui prennent en charge plusieurs régions. J'ai besoin de faire des événements de l'agenda pour un client. Donc disons que de mon site web et serveur Postgres est hébergé dans MST fuseau horaire (mais je suppose que cela pourrait être n'importe où si nous allons cloud). Mais le client est dans l'est. Donc, à la suite d'un certain nombre de meilleures pratiques que j'ai lu, j'ai pensé que je voudrais stocker tous date de fois en format UTC. Tous les champs de l'heure dans la base de données sont déclarées en tant que TIMESTAMP.
Donc, voici comment je prends un LocalDateTime et de les convertir au format UTC:
ZonedDateTime startZonedDT = ZonedDateTime.ofLocal(dto.getStartDateTime(), ZoneOffset.UTC, null);
//appointment startDateTime is a LocalDateTime
appointment.setStartDateTime( startZonedDT.toLocalDateTime() );
Maintenant , par exemple, lorsqu'un rechercher une date arrive, je dois convertir à partir de la date demandée temps UTC, obtenir les résultats et de les convertir à l'utilisateur du fuseau horaire (stockées dans la base de données):
ZoneId userTimeZone = ZoneId.of(timeZone.getID());
ZonedDateTime startZonedDT = ZonedDateTime.ofLocal(appointment.getStartDateTime(), userTimeZone, null);
dto.setStartDateTime( startZonedDT.toLocalDateTime() );
Maintenant, je ne suis pas sûr que c'est la bonne approche. Je me demande également si, parce que je vais partir LocalDateTime à ZonedDateTime et vice versa, j'ai peut-être de perdre le fuseau horaire info.
Voici ce que je vois et il ne me semble pas correct pour moi. Lorsque je reçois la LocalDateTime à partir de l'INTERFACE utilisateur, j'obtiens ceci:
2016-04-04T08:00
La ZonedDateTime =
dateTime=2016-04-04T08:00
offset="Z"
zone="Z"
Et puis, quand j'affecter cette valeur convertie à mon rendez-vous LocalDateTime je store:
2016-04-04T08:00
J'ai envie parce que je suis le stockage dans LocalDateTime je perds le fuseau horaire que j'ai converti en ZonedDateTime.
Je dois faire mon entité (rendez-vous) utilisez ZonedDateTime au lieu de LocalDateTime de sorte que Postgres ne pas perdre cette information?
---------------- Modifier ----------------
Après Basile excellente réponse, j'ai réalisé que j'ai le luxe de ne pas se soucier des utilisateurs fuseau horaire - tous les rendez-vous sont à l'encontre d'un endroit précis de sorte que je peux stocker tous date de fois que l'UTC, puis de les convertir à l'emplacement de fuseau horaire lors de la récupération. J'ai fait la suite suivi question
Concernant votre "Modifier" de l'article, à savoir que les politiciens amour pour redéfinir les zones de temps, de décalage, de l'Heure d'été (DST), etc. Donc, ne jamais aller loin dans l'avenir avec des valeurs d'UTC. Si tu parles de l'hygiène dentaire, les nominations sont faites longtemps à l'avance, ex. “3 H, le 5 décembre, 2017 plus tard cette année”, alors vous pouvez en effet de vouloir utiliser un
LocalDateTime
pour stocker ce fait. L'intention il y a 3 PM toutefois, les responsables politiques ont redéfini ce moment-là. Pour un calendrier que vous pourriez appliquer temporairement le fuseau horaire pour le potentiel LocalDateTime
pour générer un réel moment comme un ZonedDateTime
/Instant
.OriginalL'auteur sonoerin | 2016-04-05
Vous devez vous connecter pour publier un commentaire.
Postgres n'a pas un tel type de données que
TIMESTAMP
. Postgres a deux types pour date de plus de temps de la journée:TIMESTAMP WITH TIME ZONE
etTIMESTAMP WITHOUT TIME ZONE
. Ces types très différents de comportement à l'égard des informations de fuseau horaire.WITH
type utilise tout décalage ou des informations de fuseau horaire pour régler la date et l'heure de UTC, puis se débarrasse de ce décalage de temps ou de zone; Postgres n'enregistre jamais le décalage de la zone de info.WITHOUT
type ignore tout décalage ou de la zone d'infos qui peuvent être présents.Vous pratiquement toujours envie de la
WITH
type, comme expliqué ici par l'expert David E. Wheeler. LeWITHOUT
n'a de sens que lorsque vous avez l'idée vague d'une date-heure plutôt que d'un point fixe sur la timeline. Par exemple, "cette année, Noël commence à 2016-12-25T00:00:00" devraient être stockées dans laWITHOUT
tel qu'il s'applique à tout de fuseau horaire, il n'avait pas encore été appliquée à un seul fuseau horaire pour obtenir un réel moment sur la timeline. Si les lutins du père noël ont suivi la date de départ de Eugene en Oregon NOUS, alors qu'ils allaient utiliser laWITH
type et d'une entrée qui inclus un décalage de temps ou de zone tels que2016-12-25T00:00:00-08:00
qui est enregistré dans Postgres comme2016-12-25T08:00.00Z
(où leZ
signifie en Zoulou ou UTC).L'équivalent de Postgres’
TIMESTAMP WITHOUT TIME ZONE
en java.le temps estjava.time.LocalDateTime
. Que votre intention était de travailler en UTC (une bonne chose), vous devez pas utiliserLocalDateTime
(une mauvaise chose). Que peut être le point principal de la confusion et de la difficulté pour vous. Vous continuez à penser à propos de l'utilisationLocalDateTime
ouZonedDateTime
mais vous devriez être à l'aide de ni; au lieu de cela, vous devriez être en utilisantInstant
(voir ci-dessous).En effet, vous êtes. L'ensemble du point de
LocalDateTime
est à perdre fuseau horaire info. Nous avons donc rarement utiliser cette classe dans la plupart des applications. De nouveau, les fêtes de Noël par exemple. Ou un autre exemple, "la politique de l'Entreprise: l'Ensemble de nos usines à travers le monde de prendre le déjeuner à 12:30 PM". Que seraitLocalTime
, et pour une date particulière,LocalDateTime
. Mais cela n'a aucun sens réel, pas un point sur la ligne de temps, jusqu'à ce que vous appliquez une zone de temps pour obtenir unZonedDateTime
. Que la pause déjeuner sera à différents points dans le scénario de l'Delhi usine de l'usine de Düsseldorf et de différent, de nouveau, à l'usine de Detroit.Le mot "Local" dans
LocalDateTime
peut être contre-intuitif que cela signifie aucun localité. Quand vous lisez “Local” dans un nom de classe, pense que “Pas un instant... pas sur la timeline... juste une idée floue sur un kinda-sorta date-heure”.Vos serveurs doivent presque toujours être réglée sur UTC dans leur système d'exploitation de fuseau horaire. Mais votre programmation doit jamais dépendre de cette externalité comme il est trop facile pour un sysadmin pour le changer ou pour toute autre application Java pour modifier la durée par défaut de la zone à l'intérieur de la JVM. Il faut donc toujours préciser votre choix/l'heure prévue de la zone. (En va de même pour
Locale
, par la manière.)Résultat:
Au cours de la journée de travail, tout en portant votre geek hard-hat, penser en UTC. Seulement à la fin de la journée, lors du passage de votre laïc a devrait vous revenir à la pensée de l'heure locale de votre ville.
Une logique d'entreprise doit se concentrer sur l'heure UTC. Votre stockage de base de données, logique métier, l'échange de données, la sérialisation, l'exploitation forestière, et de votre propre pensée doit être fait dans le fuseau horaire UTC (et de l'horloge de 24 heures, par la voie). Lors de la présentation des données pour les utilisateurs, alors seulement d'appliquer un fuseau horaire particulier. Pensez à zoné date de fois que d'une chose extérieure, n'est pas un partie de votre app’ intérieur.
Sur le Java, utiliser des
java.temps.Instantané
(un moment sur la ligne de temps en temps UTC) dans une grande partie de votre logique métier.Espérons JDBC pilotes seront éventuellement mis à jour à traiter avec java.le temps des types comme
Instant
directement. Jusqu'alors, nous devons utiliser java.les types sql. Le vieux java.sql classe ont de nouvelles méthodes pour la conversion vers/à partir de java.temps.Maintenant passer que
java.sql.TimeStamp
de l'objet viasetTimestamp
sur unPreparedStatement
être enregistrées dans une colonne définie commeTIMESTAMP WITH TIME ZONE
dans Postgres.Aller dans l'autre direction:
De sorte que c'est facile, passant de
Instant
àjava.sql.Timestamp
àTIMESTAMP WITH TIME ZONE
, tout en UTC. Pas le temps des zones impliquées. L'actuel fuseau horaire par défaut de votre système d'exploitation serveur, votre JVM, et vos clients, tout est hors de propos.De présenter à l'utilisateur, appliquer un fuseau horaire. Utilisation fuseau horaire noms, jamais les 3-4 lettre des codes comme
EST
ouIST
.Vous pouvez régler dans une autre zone que nécessaire.
Pour revenir à un
Instant
, un moment, sur le plan chronologique de l'UTC, vous pouvez extraire de laZonedDateTime
.Pas où il n'y en a que nous utilisons
LocalDateTime
.Si vous obtenez un morceau de données sans aucun décalage de l'UTC ou de fuseau horaire, comme la
2016-04-04T08:00
, que les données est tout à fait inutile pour vous (en supposant que nous ne parlons pas de la de Noël ou de la Société le Déjeuner, type de scénarios discutés ci-dessus). Une date-heure sans décalage de la zone de l'info, c'est comme un montant monétaire, sans indiquer la devise:142.70
ou même$142.70
-- inutile. MaisUSD 142.70
, ouCAD 142.70
, ouMXN 142.70
... ceux qui sont utiles.Si vous ne obtenez ce que
2016-04-04T08:00
valeur, et vous êtes absolument certain de l'offset, de la zone de contexte, alors:LocalDateTime
.OffsetDateTime
, ou (mieux) s'appliquent à une zone de temps pour obtenir unZonedDateTime
.Comme ce code.
Votre Question est vraiment une copie de beaucoup d'autres. Ces problèmes ont été discutés à plusieurs reprises dans d'autres Questions et Réponses. Je vous exhorte à la recherche et à l'étude de Débordement de Pile pour en savoir plus sur ce sujet.
JDBC 4.2
De JDBC 4.2, nous pouvons échanger directement des java.temps objets avec la base de données. Pas besoin de toujours utiliser
java.sql.Timestamp
de nouveau, ni ses classes.Le stockage, l'utilisation
OffsetDateTime
tel que défini dans le JDBC spec....ou peut-être l'utiliser
Instant
directement, si pris en charge par votre pilote JDBC.De la récupération.
Sur java.temps
La java.temps cadre est intégré dans Java 8 et les versions ultérieures. Ces classes permettent d'éviter la pénible vieux héritage date du temps des classes comme
java.util.Date
,Agenda
, &SimpleDateFormat
.La Joda-Time projet, maintenant dans le mode de maintenance, conseille la migration vers le java.le temps classes.
Pour en savoir plus, consultez les Oracle Tutoriel. Et de recherche de Débordement de Pile pour de nombreux exemples et des explications. La spécification est JSR 310.
Vous pouvez échanger java.temps objets directement avec votre base de données. Utiliser un Pilote JDBC compatible avec JDBC 4.2 ou plus tard. Pas besoin de chaînes, pas besoin de
java.sql.*
classes.Où obtenir le java.les classes de temps?
La ThreeTen-Extra projet s'étend java.temps avec d'autres classes. Ce projet est un terrain d'essai pour de possibles futurs ajouts à java.temps. Vous pouvez trouver quelques classes utiles ici comme
Intervalle
,YearWeek
,YearQuarter
, et plus.Merci de votre réponse, Il a également résolu mon problème!
OriginalL'auteur Basil Bourque