Como explicado por outros, há uma descontinuidade no tempo lá. Existem dois desvios de fuso horário possíveis para 1927-12-31 23:54:08
at Asia/Shanghai
, mas apenas um deslocamento para1927-12-31 23:54:07
. Portanto, dependendo de qual deslocamento é usado, há uma diferença de um segundo ou de 5 minutos e 53 segundos.
Essa ligeira mudança de compensações, em vez do horário de verão habitual de uma hora (horário de verão) a que estamos acostumados, obscurece um pouco o problema.
Observe que a atualização de 2013 do banco de dados de fuso horário moveu essa descontinuidade alguns segundos antes, mas o efeito ainda seria observável.
O novo java.time
pacote no Java 8 permite ver isso mais claramente e fornece ferramentas para lidar com isso. Dado:
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());
Em seguida durationAtEarlierOffset
, será um segundo, enquanto durationAtLaterOffset
serão cinco minutos e 53 segundos.
Além disso, essas duas compensações são as mesmas:
// Both have offsets +08:05:52
ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset();
ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset();
Mas estes dois são diferentes:
// +08:05:52
ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset();
// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();
Você pode ver o mesmo problema em comparação 1927-12-31 23:59:59
com 1928-01-01 00:00:00
, no entanto, nesse caso, é o deslocamento anterior que produz a divergência mais longa e é a data anterior que tem duas compensações possíveis.
Outra maneira de abordar isso é verificar se há uma transição em andamento. Podemos fazer isso assim:
// Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);
// An overlap transition
ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime);
Você pode verificar se a transição é uma sobreposição em que há mais de um deslocamento válido para essa data / hora ou um intervalo em que essa data / hora não é válida para esse ID de zona - usando os métodos isOverlap()
e .isGap()
zot4
Espero que isso ajude as pessoas a lidar com esse tipo de problema quando o Java 8 estiver amplamente disponível ou para aqueles que usam o Java 7 que adotam o backport JSR 310.