2012-10-30 18 views
5

In seguito a un errore, ho notato che se creo un java.sql.Timestamp da un java.util.Date, utilizzando il costruttore che impiega i millisecondi, l'istanza Date è sempre successiva() al Timestamp. Questo è sconcertante, poiché (a) il contratto per before() specifica un confronto rigoroso e (b) se non è uguale, il Timestamp, poiché ha nanosecondi, potrebbe essere esso stesso dopo() la Data. Ma i risultati sono opposti e ripetibili (con JDK 1.6 e 1.7, con diversi fusi orari JVM). Il confronto di due date funziona correttamente, ma chiamare prima() o dopo() su una data e fornire un argomento Timestamp ha risultati imprevisti.java.sql.Timestamp creato da java.util.Date, perché sempre prima()?

Il seguente codice di esempio presenta due date e un'istanza di Timestamp, tutte con lo stesso valore in millisecondi. Tuttavia, confrontando una data con un timestamp, la data deve essere successiva() al timestamp.

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

uscita Esempio:

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 

L'ultima riga è il curioso.

Grazie.

+0

Utilizzare il debugger per farlo notare. E ricorda l'API [Timestamp] (http://docs.oracle.com/javase/6/docs/api/java/sql/Timestamp.html) * "[...] si raccomanda che il codice non visualizzi i valori di Timestamp genericamente come un'istanza di java.util.Date. "* – Kai

+1

' d1.compareTo (ts); 'results' 1', che indica che c'è una differenza di 1 nano o qualcosa del like. ___ Credo che sia un bug, sì. Bel lavoro a trovarlo! – XenoRo

risposta

6

Se si guarda alla rappresentazione interna e ciò che viene confrontato nel metodo after(), si vede che, per esempio per

millis = 1351607849957 

si ottiene un Date con

fastTime = 1351607849957 

e un Timestamp con

fastTime = 1351607849000 
nanos = 957000000 

Dal tutto ciò che viene confrontato è la parte fastTime, si ottiene il comportamento osservato. Come @ user714965 indica sopra, non si deve trattare uno Timestamp come Date.

+0

Ah, questo è tutto. Grazie. –

4

La documentazione API di java.sql.Timestamp dice:

Nota: Questo tipo è un composto di un java.util.Date e un valore nanosecondi separato. Solo i secondi interi sono memorizzati nel componente java.util.Date. I secondi frazionari - i nanos - sono separati.

(Ciò concorda con la risposta di Keppil).

Si dice anche:

causa delle differenze tra la classe e la classe Timestampjava.util.Date sopra menzionato, si raccomanda che il codice non visualizzare Timestamp valori genericamente come un esempio di java.util.Date. La relazione di ereditarietà tra Timestamp e java.util.Date indica in realtà l'ereditarietà dell'implementazione e non l'ereditarietà del tipo.

Ciò significa che non si dovrebbe trattare Timestamp come java.util.Date, che è quello che state facendo, se si passa a java.util.Date.after() (che metodo si aspetta un java.util.Date - si sta passando un Timestamp, trattandolo come se fosse una java.util.Date, che questo commento dice che non dovresti fare).

Questo è un cattivo design nella libreria standard di Java. Se hai bisogno di lavorare con date e orari, usa Joda Time, una libreria molto più progettata e più potente.

+0

Sì, sono a conoscenza di tali differenze (e incompatibilità, in particolare in equals()) e di Joda, ma sto cercando una spiegazione di questo strano comportamento. –

+0

Nota che puoi scavare nel codice sorgente di una classe come 'java.sql.Timestamp', puoi trovarlo nel file' src.zip' che si trova nella tua directory di installazione JDK. – Jesper

Problemi correlati