Comme expliqué par d'autres, il y a là une discontinuité temporelle. Il existe deux décalages de fuseau horaire possibles pour 1927-12-31 23:54:08
à Asia/Shanghai
, mais un seul décalage pour 1927-12-31 23:54:07
. Ainsi, selon le décalage utilisé, il y a soit une différence d'une seconde, soit une différence de 5 minutes et 53 secondes.
Ce léger décalage des décalages, au lieu de l'heure d'été habituelle (heure d'été) à laquelle nous sommes habitués, obscurcit un peu le problème.
Notez que la mise à jour 2013a de la base de données de fuseau horaire a déplacé cette discontinuité quelques secondes plus tôt, mais l'effet serait toujours observable.
Le nouveau java.time
package sur Java 8 permet de voir cela plus clairement et fournit des outils pour le gérer. Donné:
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.append(DateTimeFormatter.ISO_LOCAL_DATE);
dtfb.appendLiteral(' ');
dtfb.append(DateTimeFormatter.ISO_LOCAL_TIME);
DateTimeFormatter dtf = dtfb.toFormatter();
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
ZonedDateTime zdt3 = LocalDateTime.parse(str3, dtf).atZone(shanghai);
ZonedDateTime zdt4 = LocalDateTime.parse(str4, dtf).atZone(shanghai);
Duration durationAtEarlierOffset = Duration.between(zdt3.withEarlierOffsetAtOverlap(), zdt4.withEarlierOffsetAtOverlap());
Duration durationAtLaterOffset = Duration.between(zdt3.withLaterOffsetAtOverlap(), zdt4.withLaterOffsetAtOverlap());
Il y durationAtEarlierOffset
aura ensuite une seconde, tandis que durationAtLaterOffset
sera de cinq minutes et 53 secondes.
De plus, ces deux décalages sont identiques:
// Both have offsets +08:05:52
ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset();
ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset();
Mais ces deux sont différents:
// +08:05:52
ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset();
// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();
Vous pouvez voir le même problème par rapport 1927-12-31 23:59:59
à 1928-01-01 00:00:00
, cependant, dans ce cas, c'est le décalage antérieur qui produit la divergence la plus longue, et c'est la date antérieure qui a deux décalages possibles.
Une autre façon d'aborder cela est de vérifier s'il y a une transition en cours. Nous pouvons le faire comme ceci:
// Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);
// An overlap transition
ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime);
Vous pouvez vérifier si la transition est un chevauchement où il y a plus d'un décalage valide pour cette date / heure ou un écart où cette date / heure n'est pas valide pour cet identifiant de zone - en utilisant les méthodes isOverlap()
et .isGap()
zot4
J'espère que cela aidera les gens à gérer ce type de problème une fois que Java 8 sera largement disponible, ou à ceux qui utilisent Java 7 qui adoptent le backport JSR 310.