¿Por qué restar estas dos veces (en 1927)da un resultado extraño

java date timezone


Si ejecuto el siguiente programa,que analiza dos cadenas de fechas referidas a tiempos de 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 es 1 (como esperaría de la diferencia de un segundo en los tiempos), sino 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



Answer 1 Jon Skeet


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.

Sólo otro episodio en el a menudo extraño y maravilloso mundo de los husos horarios.

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 demuestra 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 y t+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 simplemente en su hora estándar durante cualquier instante antes del comienzo de las 1900 UTC:

import java.util.TimeZone;

public class Test {
    public static void main(String[] args) throws Exception {
        long startOf1900Utc = -2208988800000L;
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
                System.out.println(id);
            }
        }
    }
}

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 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 getRawOffset supone que es un concepto válido), por lo que otras bibliotecas no necesitan introducir esta transición artificial.




Answer 2 Michael Borgwardt


Ha encontrado una discontinuidad de hora local :

Cuando la hora local estaba a punto de llegar al domingo 1 de enero de 1928,los relojes de las 00:00:00 se retrasaron 0:05:52 horas hasta el sábado 31.Diciembre de 1927,23:54:08 hora local en su lugar

Esto no es particularmente extraño y ha sucedido prácticamente en todas partes en un momento u otro,ya que las zonas horarias fueron cambiadas o modificadas debido a acciones políticas o administrativas.




Answer 3 Raedwald


La moraleja de esta extrañeza es:

  • Utilice fechas y horas en UTC siempre que sea posible.
  • Si no puede mostrar la fecha o la hora en UTC,indique siempre la zona horaria.
  • Si no se puede exigir una fecha/hora de entrada en UTC,exigir una zona horaria explícitamente indicada.



Answer 4 PatrickO


Al incrementar el tiempo debes convertir de nuevo a UTC y luego sumar o restar.Utilice la hora local sólo para la visualización.

De esta manera podrás caminar a través de cualquier periodo en el que las horas o los minutos pasen dos veces.

Si se convirtió a UTC, agregue cada segundo y conviértalo a la hora local para mostrarlo. Debes pasar por las 11:54:08 pm LMT - 11:59:59 pm LMT y luego 11:54:08 pm CST - 11:59:59 pm CST.




Answer 5 Rajshri


En lugar de convertir cada fecha,puedes usar el siguiente código:

long difference = (sDt4.getTime() - sDt3.getTime()) / 1000;
System.out.println(difference);

Y luego ver que el resultado es:

1