2009-08-06 3 views
18

Il seguente codice sembra dimostrare un errore in java.util.Date per cui un'ora viene aggiunta se l'orologio locale è impostato su GMT con la regolazione dell'ora legale e il tempo è precedente al 1 ° novembre 1971. La mia prima ipotesi è sempre che io hai sbagliato. Qualcuno può vedere cosa c'è che non va (o è davvero un bug Java)? Qual è il significato del 1 ° novembre 1971?Perché un'ora viene aggiunta a java.util.Date per le date precedenti al 1 ° novembre 1971?

import java.text.SimpleDateFormat; 
import java.util.Locale; 
import java.util.TimeZone; 

class JavaUtilDateBug 
{ 
    private static void demo() throws Exception 
    { 
     // UK developers usually have the clock on their development machines set 
     // to "Europe/London" (i.e. GMT with daylight saving). Set it explicitly 
     // here so readers in other countries can see the problem too. 
     TimeZone.setDefault(TimeZone.getTimeZone("Europe/London")); 
     Locale.setDefault(Locale.ENGLISH); 

     SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy"); 
     String strJan1st1970Expected = "Thu Jan 01 00:00:00 GMT 1970"; 
     String strJan1st1970Actual = dateFormat.parse(strJan1st1970Expected).toString(); 
     System.out.println("strJan1st1970Actual: " + strJan1st1970Actual); // -> "Thu Jan 01 01:00:00 GMT 1970" 
     boolean jvmHasDateBug = !strJan1st1970Expected.equals(strJan1st1970Actual); 
     System.out.println("jvmHasDateBug: " + jvmHasDateBug); // -> true 

     // The anomaly only seems to affect times before 1 Nov 1971. 
     final String strNov1st1971 = "Mon Nov 01 00:00:00 GMT 1971"; 
     assert strNov1st1971.equals(dateFormat.parse(strNov1st1971).toString()); 
    } 

    public static void main(String[] args) 
    { 
     try 
     { 
      demo(); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

ambiente mia Java:

java version "1.6.0_13" 
    Java(TM) SE Runtime Environment (build 1.6.0_13-b03) 
    Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing) 
+1

Il programma di dimostrazione funziona su macchine non inglesi solo se si impostano anche le impostazioni internazionali (altrimenti l'analisi della data non riesce). –

+0

Grazie, Michael. Codice demo aggiornato. –

risposta

5

Ho trovato un matching bug nel database dei bug di Sun. Sembra che lo considerino una "inesattezza storica" ​​(la formattazione apparentemente dovrebbe produrre "BST" come fuso orario anziché GMT - l'ora sarebbe corretta) e non la risolverà, perché in fondo, l'implementazione TimeZone non può gestire i luoghi cambiare il nome del loro fuso orario.

Come soluzione temporanea, è possibile impostare in modo esplicito il proprio fuso orario su GMT anziché su "Europa/Londra". Il problema poi scompare.

+0

Il bug sembra non essere più disponibile nel database dei bug. –

13

E 'il locale. Da http://en.wikipedia.org/wiki/British_Summer_Time

lo schema del tempo standard britannico è stato sperimentato tra il 27 ottobre 1968 e il 31 ottobre 1971, quando la Gran Bretagna è rimasta sul GMT + 1 tutto l'anno.

+0

Wow, pensavo che sarebbe stato troppo oscuro per ricevere una risposta due volte ... –

+0

Bah. Ho avuto una risposta a metà quando sono stato informato dei tuoi due. –

21

C'è stata una prova del British Standard Time tra il 27 ottobre 1968 e il 31 ottobre 1971, che sospetto sia la causa del problema.

Ci sono alcuni dettagli del processo qui:

http://en.wikipedia.org/wiki/British_Summer_Time#Single.2FDouble_Summer_Time

Il fuso orario per l'Europa/Londra nel 1 GENNAIO 1970 era British Standard Time (GMT + 1) in modo che quando si utilizza un java.text.SimpleDateFormat per analizzare 1 gennaio 00:00:00 GMT 1970 genera il valore epoch corretto uguale a Jan 01 01:00:00 1970 in BST.

Poi, a causa della crappiness di java.util.Date, quando si chiama java.util.Date.toString() usa il fuso orario predefinito per la corrente locale di ora, che ha cambiato per GMT e si ottiene 1 gennaio 01:00:00 GMT 1970.

+0

Interessante. Non è ancora chiaro il motivo per cui non è simmetrico, tuttavia se si alimenta "Gio 01 00:00:00 GMT 1970" si dovrebbe ottenere lo stesso risultato. –

+0

Questo non è un problema con java.util.Date toString(), il comportamento non è diverso quando lo formatti usando lo stesso SimpleDateFormat che hai usato per l'analisi. Vedi la mia risposta per l'opinione di Sun su questo. –

+0

Hey Michael - dai un'occhiata al metodo normalize() java.util.Date. Viene chiamato dal metodo toString() e chiama TimeZone.getDefaultRef() per ottenere il fuso orario. Sembra la causa giusta? –

0

Questo non è un bug.

Si è impostato il fuso orario predefinito per BST che è (GMT + 1), la data GMT di Jan 1 1970 00:00:00, quando si analizza questa data utilizzando BST fuso orario come predefinita, visualizza sempre il tempo in base al fuso orario corrente (auto Si applica compensato da GMT) .

In questo caso era GMT + 1 ed è per questo che il risultato è stato un'ora di pausa.