Comment convertir ZonedDateTime en Date?
j'essaie de définir une date de date agnostique de serveur dans ma base de données et je crois que la meilleure pratique pour le faire est de définir un UTC DateTime. 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 la nouvelle Java 8 ZonedDateTime pour obtenir L'UTC maintenant ( ZonedDateTime.now(ZoneOffset.UTC)
), Comment puis-je convertir cette instance ZonedDateTime à la classe de Date" legacy"?
8 réponses
vous pouvez convertir ZonedDateTime en un instant, que vous pouvez utiliser directement avec la Date.
Date.from(java.time.ZonedDateTime.now().toInstant());
tl; dr
java.util.Date.from( // Transfer the moment in UTC, truncating any microseconds or nanoseconds to milliseconds.
Instant.now() ; // Capture current moment in UTC, with resolution as fine as nanoseconds.
)
bien qu'il n'y ait aucun point dans ce code ci-dessus. Les deux java.util.Date
et Instant
représentent un moment en UTC, toujours en UTC. Le Code ci-dessus a le même effet que:
new java.util.Date() // Capture current moment in UTC.
Aucun avantage ici à l'aide de ZonedDateTime
. Si vous avez déjà un ZonedDateTime
, ajustez à UTC en extrayant un Instant
.
java.util.Date.from( // Truncates any micros/nanos.
myZonedDateTime.toInstant() // Adjust to UTC. Same moment, same point on the timeline, different wall-clock time.
)
Autre Réponse Correcte
le Réponse par ssoltanid répond correctement à votre question spécifique, comment convertir un java nouvelle-école.le temps de l'objet ( ZonedDateTime
) à la une de la vieille école java.util.Date
objet. Extraire le Instant
du ZonedDateTime et passer à java.util.Date.from()
.
Perte De Données
notez que vous allez subir une perte de données , comme Instant
pistes nanosecondes depuis epoch , alors que java.util.Date
pistes millisecondes depuis l'époque.
votre Question et vos commentaires soulèvent d'autres questions.
Maintenir les Serveurs Au format UTC
vos serveurs doivent avoir leur OS hôte défini à UTC comme une pratique exemplaire en général. La JVM ramasse sur ce système d'exploitation hôte comme son fuseau horaire par défaut, dans les implémentations Java que je connais.
Spécifier Le Fuseau Horaire
mais vous ne devez jamais vous fier au fuseau horaire par défaut de la JVM. Plutôt que de prendre en compte le paramètre hôte, un drapeau 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 à n'importe quel moment peut faire un appel à java.util.TimeZone::setDefault
pour changer ce défaut à l'exécution!
Cassandra Timestamp
Type
Any decent database et le pilote devrait automatiquement gérer le réglage d'une date-heure passée à UTC pour le stockage. Je n'utilise pas Cassandra, mais il semble avoir un certain soutien rudimentaire pour date-time. La documentation dit que son type Timestamp
est un décompte de millisecondes de la même époque (premier moment de 1970 en UTC).
ISO 8601
en outre, Cassandra accepte les entrées de chaîne dans les formats standards ISO 8601 . Heureusement, java.time utilise les formats ISO 8601 par défaut pour analyser/générer des chaînes. Le Instant
classe’ toString
la mise en œuvre fera très bien l'affaire.
précision: milliseconde vs Nanosecord
Mais d'abord nous devons réduire la précision nanoseconde de ZonedDateTime à millisecondes. Une façon est de créer un nouvel Instant en utilisant des millisecondes. Heureusement, java.le temps a quelques méthodes pratiques pour convertir en millisecondes et à partir de millisecondes.
Exemple De Code
voici un exemple de code dans Java 8 Update 60.
ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
…
Instant instant = zdt.toInstant();
Instant instantTruncatedToMilliseconds = Instant.ofEpochMilli( instant.toEpochMilli() );
String fodderForCassandra = instantTruncatedToMilliseconds.toString(); // Example: 2015-08-18T06:36:40.321Z
Ou selon ce Cassandra pilote Java doc , vous pouvez passer un java.util.Date
exemple (à ne pas confondre avec java.sqlDate
). Pour que tu puisses faire un J. U. Date à partir de instantTruncatedToMilliseconds
dans le code ci-dessus.
java.util.Date dateForCassandra = java.util.Date.from( instantTruncatedToMilliseconds );
si vous le faites souvent, vous pouvez faire une doublure.
java.util.Date dateForCassandra = java.util.Date.from( zdt.toInstant() );
mais il serait plus judicieux de créer une petite méthode utilitaire.
static public java.util.Date toJavaUtilDateFromZonedDateTime ( ZonedDateTime zdt ) {
Instant instant = zdt.toInstant();
// Data-loss, going from nanosecond resolution to milliseconds.
java.util.Date utilDate = java.util.Date.from( instant ) ;
return utilDate;
}
remarquez la différence entre ce code et la Question. Le code de la Question était d'essayer d'ajuster le fuseau horaire de L'instance ZonedDateTime vers UTC. Mais ce n'est pas nécessaire. Sur le plan conceptuel:
ZonedDateTime = Instant + ZoneId
nous venons d'extraire la partie instantanée, qui est déjà en UTC (essentiellement en UTC, lire la classe doc pour plus de détails).
à Propos de de java.heure
le de java.time framework est construit dans Java 8 et plus tard. Ces classes remplacent les anciennes classes de date legacy telles que java.util.Date
, Calendar
, & SimpleDateFormat
.
Le Joda-Time , qui est maintenant dans mode maintenance , conseille la migration vers le java .temps classes.
pour en savoir plus, voir le Oracle Tutorial . Et rechercher le débordement de la pile pour de nombreux exemples et explications. La spécification est JSR 310 .
vous pouvez échanger java.temps objets directement avec votre base de données. Utiliser un pilote JDBC conforme avec JDBC 4.2 ou plus tard. Pas besoin de Chaînes, pas besoin de classes java.sql.*
.
où obtenir le java.les classes de temps?
- Java SE 8 , Java SE 9 , Java SE 10 , et plus tard
- intégré.
- fait partie de L'API Java standard avec une implémentation groupée.
- Java 9 ajoute des fonctionnalités mineures et des corrections.
- Java SE 6 et Java SE 7
- une grande partie de la java.la fonctionnalité time est rétroportée à Java 6 & 7 dans ThreeTen-Backport .
- Android
- versions ultérieures des implémentations du paquet Android du java.temps classes.
- Pour plus tôt Android (<26 ans), le ThreeTenABP le projet adapte ThreeTen-Backport (voir ci-dessus). Voir comment utiliser ThreeTenABP... .
Le ThreeTen-Extra le projet s'étend java.temps avec des cours supplémentaires. Ce projet est un terrain d'essai pour de possibles futurs ajouts à Java.temps. Vous pouvez trouver ici quelques cours utiles tels que: Interval
, YearWeek
, YearQuarter
, et plus .
voici un exemple de conversion du temps de système courant en UTC. Il s'agit de formater ZonedDateTime sous forme de chaîne de caractères, puis l'objet String sera divisé en un objet date en utilisant java.text DateFormat.
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
String dateStr = zdt.format(DATETIME_FORMATTER);
Date utcDate = null;
try {
utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr);
}catch (ParseException ex){
ex.printStackTrace();
}
si vous utilisez le ThreeTen backport pour Android et ne peut pas utiliser le plus récent Date.from(Instant instant)
(qui nécessite un minimum de API 26), Vous pouvez utiliser:
ZonedDateTime zdt = ZonedDateTime.now();
Date date = new Date(zdt.toInstant().toEpochMilli());
ou:
Date date = DateTimeUtils.toDate(zdt.toInstant());
s'il vous Plaît également lire les conseils de Basilic Bourque réponse
vous pouvez le faire en utilisant le java.les classes de temps intégrées dans Java 8 et plus tard.
ZonedDateTime temporal = ...
long epochSecond = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000);
si vous êtes intéressé par Maintenant seulement, alors il suffit d'utiliser:
Date d = new Date();
j'utilise ceci.
public class TimeTools {
public static Date getTaipeiNowDate() {
Instant now = Instant.now();
ZoneId zoneId = ZoneId.of("Asia/Taipei");
ZonedDateTime dateAndTimeInTai = ZonedDateTime.ofInstant(now, zoneId);
try {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInTai.toString().substring(0, 19).replace("T", " "));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
parce que
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
Il n'est pas du travail!!!
Si u exécute votre application dans votre ordinateur, ce n'est pas un problème. Mais si vous exécutez dans N'importe quelle région D'AWS ou de Docker ou de GCP, cela va générer des problèmes. Parce que l'ordinateur n'est pas votre fuseau horaire dans les nuages. Vous devez configurer votre fuseau horaire correctement dans le Code. Par exemple, Asie/Taipei. Puis il corrigera dans AWS ou Docker ou GCP.
public class App {
public static void main(String[] args) {
Instant now = Instant.now();
ZoneId zoneId = ZoneId.of("Australia/Sydney");
ZonedDateTime dateAndTimeInLA = ZonedDateTime.ofInstant(now, zoneId);
try {
Date ans = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInLA.toString().substring(0, 19).replace("T", " "));
System.out.println("ans="+ans);
} catch (ParseException e) {
}
Date wrongAns = Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
System.out.println("wrongAns="+wrongAns);
}
}
pour une application de docker comme beehuang a commenté que vous devriez définir votre fuseau horaire.
vous pouvez aussi utiliser aveczonesamelocal . Par exemple:
2014-07-01T00:00+02:00 [GMT+02:00] est converti par
Date.from(zonedDateTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant())
à Mar Juil 01 00:00:00 CEST 2014 et par
Date.from(zonedDateTime.toInstant())
à Lun Jun 30 22: 00:00 UTC 2014