J'essaie de définir une heure de date indépendante du serveur dans ma base de données et je pense que la meilleure pratique pour le faire est de définir une heure UTC. Mon serveur de base de données est Cassandra et le pilote de base de données pour Java ne comprend que le type de date.
Donc, en supposant que dans mon code j'utilise le nouveau Java 8 ZonedDateTime pour obtenir l'UTC now ( ZonedDateTime.now(ZoneOffset.UTC)
), comment puis-je convertir cette instance de ZonedDateTime en classe Date "héritée"?
java
java-8
java.util.date
datetime-conversion
zoneddatetime
Milen Kovachev
la source
la source
java.util.Date
etjava.sql.Date
.Réponses:
Vous pouvez convertir ZonedDateTime en un instant, que vous pouvez utiliser directement avec Date.
la source
Date
est un nombre de millisecondes depuis l'époque - donc il est lié à UTC. Si vous l' imprimez , le fuseau horaire par défaut sera utilisé, mais la classe Date n'a pas connaissance du fuseau horaire de l'utilisateur ... Voir par exemple la section "mapping" dans docs.oracle.com/javase/tutorial/datetime/iso/legacy .html Et LocalDateTime est explicitement sans référence à un fuseau horaire - ce qui peut être considéré comme déroutant ...ZonedDateTime
. Lajava.time.Instant
classe est un remplacement direct pourjava.util.Date
, les deux représentant un moment en UTC maisInstant
utilise une résolution plus fine de nanosecondes au lieu de millisecondes.Date.from( Instant.now() )
aurait dû être votre solution. Ou d'ailleurs, cenew Date()
qui a le même effet, capturer le moment actuel en UTC.tl; dr
Bien qu'il n'y ait aucun intérêt dans ce code ci-dessus. Les deux
java.util.Date
etInstant
représentent un moment en UTC, toujours en UTC. Le code ci-dessus a le même effet que:Aucun avantage ici à utiliser
ZonedDateTime
. Si vous avez déjà unZonedDateTime
, ajustez à UTC en extrayant un fichierInstant
.Autre réponse correcte
La réponse de ssoltanid répond correctement à votre question spécifique, comment convertir un objet java.time (
ZonedDateTime
) de la nouvelle école en un objet de la vieille écolejava.util.Date
. Extrayez leInstant
de ZonedDateTime et passez àjava.util.Date.from()
.Perte de données
Notez que vous subir une perte de données , comme des
Instant
pistes nanosecondes depuis l' époque enjava.util.Date
pistes millisecondes depuis l' époque.Votre question et vos commentaires soulèvent d'autres problèmes.
Gardez les serveurs en UTC
Vos serveurs doivent avoir leur système d'exploitation hôte défini sur UTC comme meilleure pratique en général. La JVM prend ce paramètre du système d'exploitation hôte comme son fuseau horaire par défaut, dans les implémentations Java dont je suis conscient.
Spécifiez le fuseau horaire
Mais vous ne devez jamais vous fier au fuseau horaire par défaut actuel de la JVM. Plutôt que de choisir le paramètre d'hôte, un indicateur passé lors du lancement d'une JVM peut définir un autre fuseau horaire. Pire encore: n'importe quel code dans n'importe quel thread de n'importe quelle application à tout moment peut faire un appel
java.util.TimeZone::setDefault
pour changer cette valeur par défaut au moment de l'exécution!Timestamp
Type de CassandraToute base de données et pilote décents doivent automatiquement gérer l'ajustement d'une date-heure passée à UTC pour le stockage. Je n'utilise pas Cassandra, mais il semble avoir un support rudimentaire pour la date-heure. La documentation indique que son
Timestamp
type est un décompte de millisecondes de la même époque (premier moment de 1970 en UTC).ISO 8601
De plus, Cassandra accepte les entrées de chaîne dans les formats standard ISO 8601 . Heureusement, java.time utilise les formats ISO 8601 par défaut pour analyser / générer des chaînes. L' implémentation de
Instant
la classetoString
fera l'affaire.Précision: Milliseconde vs Nanosecord
Mais d'abord, nous devons réduire la précision nanoseconde de ZonedDateTime à quelques millisecondes. Une façon consiste à créer un nouvel instantané en millisecondes. Heureusement, java.time propose des méthodes pratiques pour convertir vers et depuis des millisecondes.
Exemple de code
Voici un exemple de code dans Java 8 Update 60.
Ou selon ce document de pilote Java Cassandra , vous pouvez passer une
java.util.Date
instance (à ne pas confondre avecjava.sqlDate
). Vous pouvez donc créer un juDate à partir de celainstantTruncatedToMilliseconds
dans le code ci-dessus.Si vous faites cela souvent, vous pouvez créer une doublure unique.
Mais il serait plus judicieux de créer une petite méthode utilitaire.
Notez la différence dans tout ce code que dans la question. Le code de la question essayait d'ajuster le fuseau horaire de l'instance ZonedDateTime à UTC. Mais ce n'est pas nécessaire. Conceptuellement:
Nous extrayons simplement la partie Instant, qui est déjà en UTC (essentiellement en UTC, lisez la documentation de la classe pour plus de détails).
À propos de java.time
Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que
java.util.Date
,Calendar
, etSimpleDateFormat
.Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .
Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .
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.*
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 d'éventuels futurs ajouts à java.time. Vous trouverez peut - être des classes utiles ici, comme
Interval
,YearWeek
,YearQuarter
et plus .la source
Voici un exemple de conversion de l'heure système actuelle en UTC. Cela implique le formatage de ZonedDateTime en tant que String, puis l'objet String sera analysé en un objet date à l'aide de java.text DateFormat.
la source
Si vous utilisez le backport ThreeTen pour Android et que vous ne pouvez pas utiliser le plus récent
Date.from(Instant instant)
(qui nécessite au minimum l'API 26), vous pouvez utiliser:ou:
Veuillez également lire les conseils dans la réponse de Basil Bourque
la source
DateTimeUtils
classe avec les méthodes de conversion, donc j'utiliserais Date date = DateTimeUtils.toDate (zdt.toInstant ()); `. Ce n'est pas si bas niveau.Vous pouvez le faire en utilisant les classes java.time intégrées à Java 8 et versions ultérieures.
la source
Instant
s piste secondes et nanosecondes.Date
s piste en millisecondes. Cette conversion de l'un à l'autre est correcte.J'utilise ça.
Parce que
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
ça ne marche pas !!! Si vous exécutez votre application sur votre ordinateur, ce n'est pas un problème. Mais si vous exécutez dans une région d'AWS, de Docker ou de GCP, cela générera un problème. Parce que l'ordinateur n'est pas votre fuseau horaire sur le cloud. Vous devez définir votre fuseau horaire correctement dans Code. Par exemple, Asie / Taipei. Ensuite, il corrigera dans AWS ou Docker ou GCP.la source
ans=Mon Jun 18 01:07:56 CEST 2018
, ce qui est incorrect, puiswrongAns=Sun Jun 17 17:07:56 CEST 2018
, ce qui est correct.La réponse acceptée n'a pas fonctionné pour moi. La date renvoyée est toujours la date locale et non la date du fuseau horaire d'origine. Je vis à UTC + 2.
J'ai proposé deux méthodes alternatives pour obtenir la date correcte à partir d'un ZonedDateTime.
Dites que vous avez ce ZonedDateTime pour Hawaii
ou pour UTC comme demandé à l'origine
Alternative 1
Nous pouvons utiliser java.sql.Timestamp. C'est simple mais cela affectera probablement aussi l'intégrité de votre programmation
Alternative 2
Nous créons la date à partir de millis (réponse ici plus tôt). Notez que ZoneOffset locale est un must.
la source
Pour une application docker comme beehuang commentée, vous devez définir votre fuseau horaire.
Vous pouvez également utiliser withZoneSameLocal . Par exemple:
2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] est converti par
au Tue Jul 01 00:00:00 CEST 2014 et par
au lun.30 juin 22:00:00 UTC 2014
la source
Si vous n'êtes intéressé que par maintenant, utilisez simplement:
la source