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"?

55
demandé sur Ole V.V. 2015-08-28 18:15:34

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());
93
répondu Slim Soltani Dridi 2018-06-07 12:14:32

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.

diagram comparing resolutions of millisecond, microsecond, and nanosecond

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?

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 .

34
répondu Basil Bourque 2018-07-16 22:01:53

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();
    }
2
répondu Asanka Siriwardena 2015-11-23 08:58:09

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

2
répondu David Rawson 2018-06-17 20:58:13

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);
1
répondu Peter Lawrey 2016-07-22 16:22:48

si vous êtes intéressé par Maintenant seulement, alors il suffit d'utiliser:

Date d = new Date();
1
répondu Jacob Eckel 2017-07-31 17:40:22

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);
    }
}
0
répondu beehuang 2018-06-18 01:57:15

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

0
répondu dwe 2018-07-11 13:17:46