2012-10-30 23 views
5

Po błędzie zauważyłem, że jeśli utworzę java.sql.Timestamp z java.util.Date, używając konstruktora, który zajmuje milisekundy, instancja Date jest zawsze po() Znaczniku czasu. Jest to zastanawiające, ponieważ (a) kontrakt dotyczący before() określa ścisłe porównanie i (b) jeśli nie jest równy, datownik, ponieważ ma nanosekundy, może sam być po() Dacie. Ale wyniki są odwrotne i powtarzalne (z JDK 1.6 i 1.7, z różnymi strefami czasowymi JVM). Porównywanie dwóch dat działa poprawnie, ale wywoływanie przed() lub po() datowniku i podaniem argumentu Timestamp ma nieoczekiwane wyniki.java.sql.Timestamp utworzone z java.util.Date, dlaczego zawsze przed() to?

Poniższy przykładowy kod ma dwie instancje Date i one Timestamp, wszystkie z tą samą wartością milisekundy. Jednak porównanie daty z datownikiem pokazuje datę, która ma być po() Znacznik czasu.

import java.util.Date; 
import java.sql.Timestamp; 

public class X extends Date { 

    public static void main(String[] args) { 
     Date d1 = new Date(); 
     Date d2 = new Date(d1.getTime()); 
     Timestamp t = new Timestamp (d1.getTime()); 
     System.out.println ("date1 = " + d1 + " (" + d1.getTime() + ")"); 
     System.out.println ("date2 = " + d2 + " (" + d2.getTime() + ")"); 
     System.out.println ("timestamp = " + t + " (" + t.getTime() + ")"); 
     System.out.println ("d1 before d2: " + d1.before(d2)); 
     System.out.println ("d1 after d2: " + d1.after(d2)); 
     System.out.println ("d1 before ts: " + d1.before(t)); 
     System.out.println ("d1 after ts: " + d1.after(t)); //why true? 
    } 
} 

Przykładowe wyjście:

C:\>\Java\jdk1.7.0_05\bin\java X 
date1 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812) 
date2 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812) 
timestamp = 2012-10-30 10:15:59.812 (1351606559812) 
d1 before d2: false 
d1 after d2: false 
d1 before ts: false 
d1 after ts: true 

Ostatni wiersz jest ciekawa.

Dziękuję.

+0

Użyj debuggera, aby wskazać, że. I przypomnij [Timestamp API] (http://docs.oracle.com/javase/6/docs/api/java/sql/Timestamp.html) * "[...] zaleca się, aby kod nie wyświetlał wartości datownika ogólnie jako instancja java.util.Date. "* – Kai

+1

' d1.compareTo (ts); 'wyniki' 1', wskazujące, że istnieje różnica 1 nano lub coś podobnego. ___ Uważam, że to błąd, tak. Niezła robota! – XenoRo

Odpowiedz

6

Jeśli spojrzeć na reprezentację wewnętrzną i co jest porównywane w metodzie after(), widać, że na przykład dla

millis = 1351607849957 

dostaniesz Date z

fastTime = 1351607849957 

i Timestamp z

fastTime = 1351607849000 
nanos = 957000000 

Ponieważ porównuje się tylko część fastTime, otrzymujesz obserwowane zachowanie. Jako @ użytkownik714965 wskazuje powyżej, nie należy traktować Timestamp jako Date.

+0

Ah, to jest to. Dziękuję Ci. –

4

Dokumentacja API java.sql.Timestamp mówi:

Uwaga: Ten typ jest złożony z java.util.Date i oddzielnej wartości nanosekund. Tylko integralne sekundy są przechowywane w komponencie java.util.Date. Ułamkowe sekundy - nanosy - są oddzielne.

(To zgadza się z odpowiedzią Keppila).

mówi również:

Ze względu na różnice między klasą Timestamp i klasy java.util.Date wspomniano powyżej, zaleca się, że kod nie zobaczyć Timestamp wartości rodzajowo jako przykład java.util.Date. Relacja dziedziczenia między Timestamp i java.util.Date naprawdę oznacza dziedziczenie implementacji, a nie dziedziczenie typu.

Oznacza to, że nie należy traktować Timestamp jako java.util.Date, czyli to, co robisz, jeśli przekazać go do java.util.Date.after() (metoda oczekuje java.util.Date - jesteś przejazdem w Timestamp, traktując je tak, jakby to java.util.Date, który to komentarz mówi, że nie powinieneś tego robić).

To jest zły projekt w standardowej bibliotece Java. Jeśli chcesz pracować z datami i czasami, użyj Joda Time, znacznie lepiej zaprojektowanej i potężniejszej biblioteki.

+0

Tak, jestem świadomy tych różnic (i niezgodności, szczególnie w equals()), a także Joda, ale szukam wyjaśnienia tego dziwnego zachowania. –

+0

Zauważ, że możesz przekopać się na kod źródłowy klasy takiej jak 'java.sql.Timestamp', możesz go znaleźć w pliku' src.zip', który znajduje się w katalogu instalacyjnym JDK. – Jesper

Powiązane problemy