web-dev-qa-db-fra.com

Java 8 date-heure: commence le jour à partir de ZonedDateTime

Y a-t-il une différence entre ceux-ci:

zonedDateTime.truncatedTo(ChronoUnit.DAYS);

zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());

Une raison de préférer l'un contre l'autre?

Merci

53
Nazaret K.

Mis à jour à des fins de correction:

Dans la plupart des cas, oui, le même , voir l'exemple suivant pour le Brésil lors du passage de l'heure d'été à l'heure d'été:

ZonedDateTime zdt = 
  ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, 
    ZoneId.of("America/Sao_Paulo")); // switch to summer time
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo]
System.out.println(zdt1); // 2015-10-18T01:00-02:00[America/Sao_Paulo]
System.out.println(zdt2); // 2015-10-18T01:00-02:00[America/Sao_Paulo]

La troncature se produit sur la timeline locale. Si vous choisissez DAYS, vous optez pour minuit. Selon javadoc , la méthode truncate()- est finalement reconvertie dans le nouveau ZonedDateTime et décale le temps de la taille de l'écart (1 heure).

Convertir le zdt en premier en LocalDate (couper la partie heure) puis en recherchant sa partie ZonedDateTime dans un fuseau horaire donné est en fait identique pour cette situation.

Cependant, dans le cas inverse du passage de l'heure d'été à l'heure d'hiver, il existe une exception (merci beaucoup à @Austin qui a donné un exemple contraire). . Le problème est lors du chevauchement quand décider quel décalage utiliser. Généralement, la classe ZonedDateTime est conçue/spécifiée pour utiliser le décalage précédent, voir aussi cet extrait de Javadoc :

Pour les chevauchements, la stratégie générale est la suivante: si le décalage horaire local tombe au milieu d'un chevauchement, le décalage précédent sera conservé. S'il n'y a pas de décalage précédent ou si le décalage précédent est invalide, le décalage précédent est utilisé, généralement une heure "été".

Si la classe ZonedDateTime suivait par conséquent ses propres spécifications, les deux procédures seraient toujours équivalentes, ce qui signifie:

zdt.truncatedTo(ChronoUnit.DAYS);

devrait être équivalent à

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();

Mais le comportement réel selon l'exemple de @Austin et confirmé par mes propres tests est le suivant:

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();

Cela ressemble à une incohérence cachée dans la classe ZonedDateTime, légèrement parlé. Si vous me demandez quelle méthode choisir, je préférerais plutôt utiliser la deuxième méthode, même si elle est beaucoup plus longue et nécessite davantage de frappes au clavier. Mais il a le gros avantage d’être plus transparent sur ce qu’il fait. Une autre raison de préférer la deuxième approche est:

Il obtient vraiment le PREMIER instant où l'heure locale est égale au début de la journée. Sinon, lorsque vous utilisez la première méthode, vous devez écrire:

zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();
48
Meno Hochschild

Ils sont légèrement différents. Selon les javadocs, truncatedTo() essaiera de préserver le fuseau horaire en cas de chevauchement, mais atStartOfDay() trouvera le première occurrence de minuit.

Par exemple, Cuba rétablit l'heure d'été à 1 heure du matin et retombe à 12 heures. Si vous commencez avec un temps après cette transition, atStartOfDay() renverra la première occurrence de 12h, tandis que truncatedTo() renverra la seconde occurrence.

ZonedDateTime zdt = ZonedDateTime.of(2016, 11, 6, 2, 0, 0, 0, ZoneId.of("America/Havana"));
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt);  // 2016-11-06T02:00-05:00[America/Havana]
System.out.println(zdt1); // 2016-11-06T00:00-05:00[America/Havana]
System.out.println(zdt2); // 2016-11-06T00:00-04:00[America/Havana]
31
Austin

Notez qu'il y a aussi une autre façon de le faire:

zonedDateTime.with(LocalTime.MIN);

qui produit le même résultat que truncatedTo

6
nevster