Si ejecuto el siguiente programa, que analiza dos cadenas de fecha que hacen referencia a 1 segundo de diferencia y las 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);
}
El resultado es:
353
¿Por qué ld4-ld3
no lo es 1
(como esperaría de la diferencia de un segundo en los tiempos), pero 353
?
Si cambio las fechas a veces 1 segundo después:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Entonces ld4-ld3
será 1
.
Versión de 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
Respuestas:
Es un cambio de zona horaria el 31 de diciembre en Shanghai.
Vea esta página para detalles de 1927 en Shanghai. Básicamente, a medianoche a fines de 1927, los relojes retrocedieron 5 minutos y 52 segundos. Entonces "1927-12-31 23:54:08" en realidad sucedió dos veces, y parece que Java lo analiza como el último instante posible para esa fecha / hora local, de ahí la diferencia.
Solo otro episodio en el mundo a menudo extraño y maravilloso de las zonas horarias.
EDITAR: ¡ Deja de presionar! La historia cambia ...
La pregunta original ya no demostraría el mismo comportamiento, si se reconstruye con la versión 2013a de TZDB . En 2013a, el resultado sería 358 segundos, con un tiempo de transición de 23:54:03 en lugar de 23:54:08.
Solo me di cuenta de esto porque estoy recopilando preguntas como esta en Noda Time, en forma de pruebas unitarias ... La prueba ahora se ha cambiado, pero solo muestra que ni siquiera los datos históricos son seguros.
EDITAR: la historia ha cambiado de nuevo ...
En TZDB 2014f, el tiempo del cambio se ha movido a 1900-12-31, y ahora es solo un cambio de 343 segundos (por lo que el tiempo entre
t
yt+1
es 344 segundos, si entiendes lo que quiero decir).EDITAR: Para responder una pregunta sobre una transición en 1900 ... parece que la implementación de la zona horaria de Java trata todas las zonas horarias como si estuvieran en su hora estándar durante cualquier instante antes del comienzo de las 1900 UTC:
El código anterior no produce resultados en mi máquina Windows. Por lo tanto, cualquier zona horaria que tenga un desplazamiento diferente al estándar a principios de 1900 contará eso como una transición. TZDB en sí tiene algunos datos que se remontan antes de eso, y no se basa en ninguna idea de un tiempo estándar "fijo" (que es lo que se
getRawOffset
supone que es un concepto válido), por lo que otras bibliotecas no necesitan introducir esta transición artificial.fuente
Ha encontrado una discontinuidad de hora local :
Esto no es particularmente extraño y ha sucedido prácticamente en todas partes en un momento u otro a medida que las zonas horarias se cambiaron o cambiaron debido a acciones políticas o administrativas.
fuente
La moraleja de esta extrañeza es:
fuente
Al incrementar el tiempo, debe volver a convertir a UTC y luego sumar o restar. Use la hora local solo para mostrar.
De esta manera, podrá caminar a través de cualquier período en el que las horas o los minutos sucedan dos veces.
Si se convirtió a UTC, agregue cada segundo y conviértalo a la hora local para mostrarlo. Usted pasaría por las 11:54:08 pm LMT - 11:59:59 pm LMT y luego 11:54:08 pm CST - 11:59:59 pm CST.
fuente
En lugar de convertir cada fecha, puede usar el siguiente código:
Y luego ver que el resultado es:
fuente
1
, porque tenemos diferentes configuraciones regionales.Lamento decirlo, pero la discontinuidad del tiempo se ha movido un poco
JDK 6 hace dos años, y en JDK 7 recientemente en la actualización 25 .
Lección que debe aprender: evite a toda costa los horarios que no sean UTC, excepto tal vez para la exhibición.
fuente
Como explicaron otros, hay una discontinuidad de tiempo allí. Hay dos posibles compensaciones de zona horaria para
1927-12-31 23:54:08
atAsia/Shanghai
, pero solo una compensación para1927-12-31 23:54:07
. Entonces, dependiendo de qué desplazamiento se use, hay una diferencia de un segundo o una diferencia de 5 minutos y 53 segundos.Este ligero cambio de compensaciones, en lugar del habitual horario de verano de una hora (horario de verano), oscurece un poco el problema.
Tenga en cuenta que la actualización 2013a de la base de datos de zonas horarias movió esta discontinuidad unos segundos antes, pero el efecto aún sería observable.
El nuevo
java.time
paquete en Java 8 permite ver esto más claramente y proporciona herramientas para manejarlo. Dado:Luego
durationAtEarlierOffset
será un segundo, mientrasdurationAtLaterOffset
que serán cinco minutos y 53 segundos.Además, estas dos compensaciones son las mismas:
Pero estos dos son diferentes:
Se puede ver el mismo problema comparando
1927-12-31 23:59:59
con1928-01-01 00:00:00
, sin embargo, en este caso, es la compensación temprana que produce la divergencia más tiempo, y es la fecha más temprana que tiene dos posibles desplazamientos.Otra forma de abordar esto es verificar si hay una transición en curso. Podemos hacer esto así:
Puede verificar si la transición es una superposición donde hay más de un desplazamiento válido para esa fecha / hora o una brecha donde esa fecha / hora no es válida para esa identificación de zona, utilizando los métodos
isOverlap()
yisGap()
enzot4
.Espero que esto ayude a las personas a manejar este tipo de problemas una vez que Java 8 esté ampliamente disponible, o para aquellos que usan Java 7 que adopten el backport JSR 310.
fuente
1900-12-31 23:54:16
y1900-12-31 23:54:17
, pero eso no funciona en el sitio que compartiste, por lo que están usando una versión de Java diferente a la mía.En mi humilde opinión, la localización generalizada e implícita en Java es su mayor defecto de diseño. Puede estar destinado a interfaces de usuario, pero, francamente, quién realmente usa Java para interfaces de usuario hoy en día, excepto algunos IDE donde básicamente puede ignorar la localización porque los programadores no son exactamente el público objetivo para ella. Puede solucionarlo (especialmente en servidores Linux):
A los miembros de Java Community Process les recomiendo:
Quiero decir, vamos, ¿no son las variables estáticas globales un patrón anti-OO? Nada más son esos valores predeterminados generalizados dados por algunas variables de entorno rudimentarias .......
fuente
Como otros dijeron, es un cambio de hora en 1927 en Shanghai.
Cuando estaba
23:54:07
en Shanghai, la hora estándar local, pero después de 5 minutos y 52 segundos, pasó al día siguiente a las00:00:00
, y luego la hora estándar local volvió a cambiar23:54:08
. Por eso, la diferencia entre los dos tiempos es 343 segundos, no 1 segundo, como era de esperar.El tiempo también puede arruinar en otros lugares como los Estados Unidos. Estados Unidos tiene horario de verano. Cuando comienza el horario de verano, el tiempo avanza 1 hora. Pero después de un tiempo, el horario de verano termina y retrocede 1 hora a la zona horaria estándar. Entonces, a veces, cuando se comparan los tiempos en los EE. UU., La diferencia es aproximadamente
3600
segundos, no 1 segundo.Pero hay algo diferente en estos dos cambios de tiempo. El último cambia continuamente y el primero fue solo un cambio. No volvió a cambiar ni volvió a cambiar en la misma cantidad.
Es mejor usar UTC donde el tiempo no cambia a menos que sea necesario usar un tiempo que no sea UTC como en la pantalla.
fuente