Se eu executar o programa a seguir, que analisa duas seqüências de datas fazendo referência a tempos com um segundo de diferença e as compara:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
A saída é:
353
Por que ld4-ld3
não é 1
(como eu esperaria da diferença de um segundo nos tempos), mas 353
?
Se eu alterar as datas para horários 1 segundo depois:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Então ld4-ld3
será 1
.
Versão Java:
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
Timezone(`TimeZone.getDefault()`):
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]
Locale(Locale.getDefault()): zh_CN
Respostas:
É uma mudança de fuso horário no dia 31 de dezembro em Xangai.
Veja esta página para detalhes de 1927 em Xangai. Basicamente, à meia-noite do final de 1927, os relógios retrocederam 5 minutos e 52 segundos. Então "1927-12-31 23:54:08" realmente aconteceu duas vezes, e parece que o Java está analisando-o mais tarde instante possível para a data / hora local - daí a diferença.
Apenas mais um episódio no mundo muitas vezes estranho e maravilhoso dos fusos horários.
EDIT: Pare de pressionar! O histórico muda ...
A pergunta original não demonstraria mais o mesmo comportamento, se reconstruída com a versão 2013a do TZDB . Em 2013a, o resultado seria 358 segundos, com um tempo de transição de 23:54:03 em vez de 23:54:08.
Eu só notei isso porque estou coletando perguntas como essa no Noda Time, na forma de testes de unidade ... O teste agora foi alterado, mas é apenas para mostrar - nem mesmo dados históricos são seguros.
EDIT: História mudou novamente ...
No TZDB 2014f, o tempo da mudança mudou para 1900-12-31, e agora é apenas uma mudança de 343 segundos (portanto, o tempo entre
t
et+1
é 344 segundos, se você entende o que eu quero dizer).EDIT: Para responder a uma pergunta sobre uma transição em 1900 ... parece que a implementação do fuso horário Java trata todos os fusos horários como estando simplesmente no horário padrão por qualquer instante antes do início de 1900 UTC:
O código acima não produz resultados na minha máquina Windows. Portanto, qualquer fuso horário que possua outro deslocamento que não seja o padrão no início de 1900 contará isso como uma transição. O próprio TZDB possui alguns dados voltando antes disso e não se baseia em nenhuma idéia de um tempo padrão "fixo" (que é o que
getRawOffset
assume ser um conceito válido), portanto outras bibliotecas não precisam introduzir essa transição artificial.fonte
Você encontrou uma descontinuidade na hora local :
Isso não é particularmente estranho e aconteceu praticamente em todos os lugares ao mesmo tempo, pois os fusos horários foram trocados ou alterados devido a ações políticas ou administrativas.
fonte
A moral dessa estranheza é:
fonte
Ao incrementar o tempo, você deve voltar ao UTC e adicionar ou subtrair. Use a hora local apenas para exibição.
Dessa forma, você poderá percorrer todos os períodos em que horas ou minutos acontecem duas vezes.
Se você tiver convertido para UTC, adicione cada segundo e converta para a hora local para exibição. Você passaria das 23h54m - 23h59m da LMT - 23h59m59m da LMT e, em seguida, das 23:54:08 pm da CST - 23h59m59s da CST.
fonte
Em vez de converter cada data, você pode usar o seguinte código:
E então veja que o resultado é:
fonte
1
, porque temos localidades diferentes.Lamento dizer, mas a descontinuidade do tempo mudou um pouco
JDK 6 há dois anos e no JDK 7 recentemente na atualização 25 .
Lição a aprender: evite horários fora do UTC a todo custo, exceto talvez para exibição.
fonte
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
atAsia/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:Em seguida
durationAtEarlierOffset
, será um segundo, enquantodurationAtLaterOffset
serão cinco minutos e 53 segundos.Além disso, essas duas compensações são as mesmas:
Mas estes dois são diferentes:
Você pode ver o mesmo problema em comparação
1927-12-31 23:59:59
com1928-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:
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.
fonte
1900-12-31 23:54:16
e1900-12-31 23:54:17
, mas isso não funciona no site que você compartilhou, portanto eles estão usando uma versão Java diferente da que eu.IMHO, a localização generalizada e implícita em Java é sua maior falha de design. Pode ser destinado a interfaces de usuário, mas, francamente, quem realmente usa Java para interfaces de usuário hoje, exceto em alguns IDEs, nos quais você pode basicamente ignorar a localização porque os programadores não são exatamente o público-alvo para ela. Você pode corrigi-lo (especialmente em servidores Linux):
Para os membros do Java Community Process , eu recomendo:
Quero dizer, vamos lá, as variáveis estáticas globais não são um padrão anti-OO? Nada mais são os padrões generalizados dados por algumas variáveis de ambiente rudimentares .......
fonte
Como outros disseram, é uma mudança de horário em 1927 em Xangai.
Quando estava
23:54:07
em Xangai, o horário padrão local, mas após 5 minutos e 52 segundos, passou para o dia seguinte às00:00:00
, e o horário padrão local mudou novamente para23:54:08
. Portanto, é por isso que a diferença entre os dois tempos é de 343 segundos e não 1 segundo, como você esperaria.O tempo também pode atrapalhar em outros lugares como os EUA. Os EUA têm horário de verão. Quando o horário de verão começa, o horário avança 1 hora. Mas, depois de um tempo, o horário de verão termina e volta 1 hora para o fuso horário padrão. Então, às vezes, ao comparar os tempos nos EUA, a diferença é de
3600
segundos e não de 1 segundo.Mas há algo diferente nessas duas mudanças de tempo. O último muda continuamente e o primeiro foi apenas uma mudança. Não mudou de volta ou mudou de novo na mesma quantidade.
É melhor usar o UTC onde o tempo não muda, a menos que seja necessário usar o horário não UTC, como no visor.
fonte