7 votes

Confusion avec Java Time parsing UTC

Je suis confus avec la gestion du temps en java time. J'ai longtemps travaillé en supposant que si un horodatage est spécifié en tant qu'heure zulu, java se chargeait du décalage par rapport à l'heure locale.

Pour illustrer. Je suis actuellement en BST qui a un décalage de UTC +1. Avec cela en tête, je m'attendrais à cette heure zoulou :

2016-09-12T13:15:17.309Z

à être

2016-09-12T14:15:17.309 

LocalDateTime après l'avoir analysé. Cela est dû au fait que mon heure système par défaut est définie sur BST et que l'horodatage ci-dessus (heure zoulou) spécifie qu'il s'agit d'une heure UTC.

Mais considérez plutôt cet échantillon :

        String ts = "2016-09-12T13:15:17.309Z";
        LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);

Cela va s'imprimer :

2016-09-12T13:15:17.309

Ainsi, le timestamp, analysé comme un LocalDateTime, n'est pas reconnu comme une heure UTC et est traité directement comme une heure locale. J'ai donc pensé que je devais peut-être l'analyser comme un ZonedDateTime et le convertir en LocalDateTime afin d'obtenir l'heure locale correcte. Avec ce test :

        String ts = "2016-09-12T13:15:17.309Z";
        ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);
        System.out.println(parse.toLocalDateTime());

Je reçois les sorties :

2016-09-12T13:15:17.309Z
2016-09-12T13:15:17.309

Même résultat pour les deux dates.

La seule façon d'analyser correctement ceci que j'ai pu trouver, est :

    String ts = "2016-09-12T13:15:17.309Z";
    Instant instant = Instant.parse(ts); // parses UTC
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(instant);
    System.out.println(ofInstant);

Cette empreinte :

2016-09-12T13:15:17.309Z
2016-09-12T14:15:17.309

Ce qui est correct.

La ou les questions sont donc les suivantes :

  • Le temps java ne devrait-il pas reconnaître un timestamp UTC et l'analyser en fonction du système correct par défaut ?
  • Comment puis-je utiliser le LocalDateTime#parse pour obtenir un résultat correct ?
  • Dois-je utiliser Instant pour tout maintenant et abandonner l'analyse syntaxique ?

Le problème est que jersey/jackson Les modules de temps java de l'entreprise analysent les horodatages en utilisant le format ISO et le format régulier LocalDateTime#parse méthodes. Je me suis rendu compte que mon temps n'est pas compté puisqu'il est traité comme LocalTime alors qu'en fait ils sont à l'heure zouloue.

6voto

Michaela Elschner Points 628

Vous comprenez mal le but de LocalDateTime .

Pour citer la documentation de la classe :

Une date-heure sans fuseau horaire dans le système de calendrier ISO-8601, telle que {@code 2007-12-03T10:15:30}.

Cette classe ne stocke ni ne représente un fuseau horaire. Il s'agit plutôt d'une description de la date, telle qu'elle est utilisée pour les anniversaires, combinée à l'heure locale telle qu'elle apparaît sur une horloge murale. Elle ne peut pas représenter un instant sur la ligne de temps sans informations supplémentaires telles qu'un décalage ou un fuseau horaire.

Son but explicite est donc de représenter une date et une heure. sans un fuseau horaire. Son objectif est le suivant no pour représenter une date et une heure dans le fuseau horaire local .

Par conséquent, chaque conversion ne fait que supprimer le fuseau horaire.

Donc, pour vos besoins, vous avez besoin d'un ZonedDateTime con ZoneId.systemDefault() comme vous l'avez déjà utilisé dans votre troisième exemple.

Pour votre deuxième exemple, cela pourrait être :

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME)
        .withZoneSameInstant(ZoneId.systemDefault());
System.out.println(parse);
System.out.println(parse.toLocalDateTime());

3voto

Basil Bourque Points 8938

Tl;dr

Exemple :

Instant.parse( "2016-09-12T13:15:17.309Z" )
       .atZone( ZoneId.of( "Europe/London" ) )
       .toString();

2016-09-12T14:15:17.309+01:00[Europe/London]

Exécuter dans IdeOne.com .

Détails

En Réponse de Krüske est correct. Vous comprenez mal la signification de LocalDateTime la classe. Elle fait no représente la date-heure d'une localité particulière. Au contraire, il ne no ne représente pas du tout un moment réel.

Je suggère de penser à Instant comme votre classe de base dans java.time. Le site Instant représente un moment sur la ligne de temps dans UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale).

Votre chaîne d'entrée est conforme au format ISO 8601 utilisé par défaut dans l'application Instant pour l'analyse syntaxique et la génération de représentations de chaînes de caractères. Le site Z à l'extrémité est le diminutif de Zulu et signifie UTC. Il n'est pas nécessaire de spécifier un modèle de formatage.

Instant instant = Instant.parse( "2016-09-12T13:15:17.309Z" );

En tant que programmeur, vous devez apprendre à penser et à travailler en UTC principalement. Oubliez votre propre fuseau horaire. Considérez l'UTC comme le seul vrai temps. Appliquez un fuseau horaire comme une variation, et seulement si nécessaire.

Indiquez un nom du fuseau horaire approprié au format de continent/region comme America/Montreal , Africa/Casablanca o Pacific/Auckland . N'utilisez jamais l'abréviation de 3-4 lettres telle que BST o EST o IST car il ne s'agit pas de véritables fuseaux horaires, ils ne sont pas normalisés et ne sont même pas uniques ( !). Si par BST vous vouliez dire l'heure d'été britannique, alors le nom du fuseau horaire réel serait Europe/London . Les classes java.time détermineront comment s'adapter à toute anomalie, y compris l'heure d'été (DST).

ZoneId z = ZoneId.of( "Europe/London" );
ZonedDateTime zdt = instant.atZone( z );

À propos de java.time

En java.time est intégré à Java 8 et aux versions ultérieures. Ces classes remplacent les anciennes classes héritage les classes de date et d'heure telles que java.util.Date , Calendar , & SimpleDateFormat .

En Joda-Time Le projet, actuellement en mode de maintenance conseille la migration vers java.time.

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez sur Stack Overflow de nombreux exemples et explications. La spécification est JSR 310 .

Où obtenir les classes java.time ?

  • Java SE 8 y SE 9 et plus tard
    • Intégré.
    • Fait partie de l'API Java standard avec une mise en œuvre groupée.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 y SE 7
    • Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 & 7 dans Trois Dix-Backport .
  • Android

En Trois-Dix-Extra Le projet étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour d'éventuels ajouts futurs à java.time. Vous pouvez y trouver des classes utiles telles que Interval , YearWeek , YearQuarter et plus .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X