2012-10-30 5 views
5

Nach einem Fehler habe ich festgestellt, dass, wenn ich einen java.sql.Timestamp aus einer java.util.Date mit dem Konstruktor erzeuge, der die Millisekunden dauert, die Date-Instanz immer nach() dem Timestamp ist. Dies ist rätselhaft, da (a) der Vertrag für vor() einen strikten Vergleich angibt und (b) wenn nicht gleich, der Zeitstempel, da er Nanosekunden hat, selbst nach() dem Datum sein könnte. Aber die Ergebnisse sind entgegengesetzt und wiederholbar (mit JDK 1.6 und 1.7, mit verschiedenen JVM-Zeitzonen). Das Vergleichen von zwei Daten funktioniert ordnungsgemäß, aber das Aufrufen von before() oder after() für ein Date und das Geben eines Timestamp-Arguments führt zu unerwarteten Ergebnissen.java.sql.Timestamp erstellt von java.util.Date, warum immer vor() es?

Der folgende Beispielcode enthält zwei Date- und eine Timestamp-Instanz, alle mit demselben Millisekundenwert. Das Vergleichen eines Datums mit einem Zeitstempel zeigt jedoch das Datum an, das nach() dem Zeitstempel sein soll.

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? 
    } 
} 

Beispielausgabe:

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 

Die letzte Zeile ist die Neugierigen ein.

Vielen Dank.

+0

Verwenden Sie den Debugger, um darauf hinzuweisen. Und erinnern Sie sich an die [Timestamp API] (http://docs.oracle.com/javase/6/docs/api/java/sql/Timestamp.html) * "[...] es wird empfohlen, dass der Code Timestamp-Werte nicht anzeigt generisch als Instanz von java.util.Date. "* – Kai

+1

' d1.compareTo (ts); 'results' 1', was darauf hinweist, dass es einen Unterschied von 1 Nano oder etwas ähnliches gibt. ___ Ich glaube, es ist ein Fehler, ja. Nette Arbeit, es zu finden! – XenoRo

Antwort

6

Wenn Sie bei der internen Darstellung aussehen und was in den after() Verfahren verglichen wird, sehen Sie, dass zum Beispiel für

millis = 1351607849957 

Sie bekommen Date mit

fastTime = 1351607849957 

und einem Timestamp mit

fastTime = 1351607849000 
nanos = 957000000 

Seit alles, was verglichen wird, ist der fastTime Teil, erhalten Sie Ihr beobachtetes Verhalten. Wie @ user714965 oben erwähnt, sollten Sie keine Timestamp als Date behandeln.

+0

Ah, das ist es. Vielen Dank. –

4

Die API-Dokumentation von java.sql.Timestamp sagt:

Hinweis: Diese Art ein Verbund aus einem java.util.Date ist und ein separater ns Wert. In der Komponente java.util.Date sind nur ganzzahlige Sekunden gespeichert. Die Bruchsekunden - die Nanos - sind getrennt.

(Das stimmt mit Keppils Antwort überein).

Er sagt auch:

Aufgrund der Unterschiede zwischen der Timestamp Klasse und der Klasse java.util.Date oben erwähnt, ist es empfehlenswert, dass Code Timestamp Werte allgemein als eine Instanz von java.util.Date nicht anzeigen. Die Vererbungsbeziehung zwischen Timestamp und java.util.Date bedeutet wirklich Implementierungsvererbung und keine Typvererbung.

Das bedeutet, sollten Sie nicht Timestamp als java.util.Date behandeln, das ist, was Sie tun, wenn Sie es java.util.Date.after() passieren (das Verfahren ein java.util.Date erwartet - Sie vorbei in einem Timestamp, es zu behandeln, als ob es ein ist java.util.Date, die dieser Kommentar sagt, sollten Sie nicht tun).

Dies ist natürlich schlechtes Design in der Standard-Java-Bibliothek. Wenn Sie mit Datum und Uhrzeit arbeiten müssen, verwenden Sie Joda Time, eine viel besser gestaltete und leistungsfähigere Bibliothek.

+0

Ja, mir sind diese Unterschiede (und Inkompatibilitäten, besonders in equals()) genauso bekannt wie Joda, aber ich suche nach einer Erklärung für dieses seltsame Verhalten. –

+0

Beachten Sie, dass Sie in den Quellcode einer Klasse wie 'java.sql.Timestamp' eintauchen können. Sie finden ihn in der Datei' src.zip', die sich in Ihrem JDK-Installationsverzeichnis befindet. – Jesper

Verwandte Themen