2009-02-24 6 views
10

favor incluya los nanos, de lo contrario sería trivial:¿Cómo calcular la diferencia entre dos Java java.sql.Timestamps?

long diff = Math.abs(t1.getTime() - t2.getTime()); 

[EDIT] Quiero que el resultado más preciso, por lo que no se duplica; solo aritmética entera/larga. Además, el resultado debe ser positivo. código Pseudo:

Timestamp result = abs (t1 - t2); 

Ejemplos:

t1 = (time=1001, nanos=1000000), t2 = (time=999, nanos=999000000) 
-> diff = (time=2, nanos=2000000) 

Sí, milisegundos en java.sql.Timestamp se duplican en el tiempo y la nanos par, por lo que 1001 milisegundos significa 1 segundo (1000) y 1 milli que está en la parte time y la parte nanos porque 1 milisegundo = 1000000 nanosegundos). Esto es mucho más tortuoso de lo que parece.

me sugieren no enviar una respuesta sin llegar a probar el código o tener un ejemplo de código de trabajo listo :)

+0

Así ¿tiene una solución que va a publicar si nadie la obtiene? –

+0

De acuerdo con los comentarios en el código fuente de Timestamp, la parte millis no está realmente duplicada en los nanos. En cambio, solo hasta los segundos se almacenan en la superclase de java.lang.Date, y los nanos proporcionan el resto del tiempo. – Richard

+0

@mmyers: Estaba trabajando en uno, pero esperaba que alguien tuviera un ejemplo de trabajo que salve mi pobre cerebro ... pero debería haber supuesto que nadie tiene cuando Google no contestó nada, pero t1.getTime() - t2 .getTime() –

Respuesta

10

Después de una hora y varias pruebas de unidad, se me ocurrió con esta solución:

public static Timestamp diff (java.util.Date t1, java.util.Date t2) 
{ 
    // Make sure the result is always > 0 
    if (t1.compareTo (t2) < 0) 
    { 
     java.util.Date tmp = t1; 
     t1 = t2; 
     t2 = tmp; 
    } 

    // Timestamps mix milli and nanoseconds in the API, so we have to separate the two 
    long diffSeconds = (t1.getTime()/1000) - (t2.getTime()/1000); 
    // For normals dates, we have millisecond precision 
    int nano1 = ((int) t1.getTime() % 1000) * 1000000; 
    // If the parameter is a Timestamp, we have additional precision in nanoseconds 
    if (t1 instanceof Timestamp) 
     nano1 = ((Timestamp)t1).getNanos(); 
    int nano2 = ((int) t2.getTime() % 1000) * 1000000; 
    if (t2 instanceof Timestamp) 
     nano2 = ((Timestamp)t2).getNanos(); 

    int diffNanos = nano1 - nano2; 
    if (diffNanos < 0) 
    { 
     // Borrow one second 
     diffSeconds --; 
     diffNanos += 1000000000; 
    } 

    // mix nanos and millis again 
    Timestamp result = new Timestamp ((diffSeconds * 1000) + (diffNanos/1000000)); 
    // setNanos() with a value of in the millisecond range doesn't affect the value of the time field 
    // while milliseconds in the time field will modify nanos! Damn, this API is a *mess* 
    result.setNanos (diffNanos); 
    return result; 
} 

Las pruebas unitarias:

Timestamp t1 = new Timestamp (0); 
    Timestamp t3 = new Timestamp (999); 
    Timestamp t4 = new Timestamp (5001); 
    // Careful here; internally, Java has set nanos already! 
    t4.setNanos (t4.getNanos() + 1); 

    // Show what a mess this API is... 
    // Yes, the milliseconds show up in *both* fields! Isn't that fun? 
    assertEquals (999, t3.getTime()); 
    assertEquals (999000000, t3.getNanos()); 
    // This looks weird but t4 contains 5 seconds, 1 milli, 1 nano. 
    // The lone milli is in both results ... 
    assertEquals (5001, t4.getTime()); 
    assertEquals (1000001, t4.getNanos()); 

    diff = DBUtil.diff (t1, t4); 
    assertEquals (5001, diff.getTime()); 
    assertEquals (1000001, diff.getNanos()); 

    diff = DBUtil.diff (t4, t3); 
    assertEquals (4002, diff.getTime()); 
    assertEquals (2000001, diff.getNanos()); 
+0

Después de mucho intentarlo, no puedo obtener que la versión BigInteger de mi código sea menos de tres veces más lenta que su código. Esto merece un voto positivo. –

+0

Gracias :) La ventaja del código BigInt es que es una sola línea (y más fácil de entender). Es por eso que le di un +1. –

3

¿En qué unidades? su diferencia anterior dará milisegundos, Timestamp.nanos() devuelve un int, que sería en (millonésimas?) de un milisegundo. Entonces, ¿quiere decir que p. ej.

(t1.getTime() + (.000001*t1.getNanos()) - (t2.getTime() + (.000001*t2.getNanos()) 

o me está faltando algo? Otra pregunta es ¿necesitas este nivel de precisión? AFAIK no garantiza que la JVM sea precisa en este nivel, no creo que importe a menos que esté seguro de que su fuente de datos es tan precisa.

+1

Faltan dos)) al final. –

+0

Me gustaría obtener un resultado exacto, por favor. –

+0

Gracias por el esfuerzo; He publicado una solución exacta, pero chico, esa API es un * desastre * –

0

(código antiguo eliminado para acortar respuesta)

EDIT 2: Nuevo código:

public class ArraySizeTest { 
    public static void main(String[] args) throws InterruptedException { 
     Timestamp t1 = new Timestamp(System.currentTimeMillis()); 
     t1.setNanos(t1.getNanos() + 60); 
     Thread.sleep(20); 
     Timestamp t2 = new Timestamp(System.currentTimeMillis()); 
     t2.setNanos(t2.getNanos() + 30); 
     System.out.println(t1); 
     System.out.println(t2); 
     // The actual diff... 
     long firstTime = (getTimeNoMillis(t1) * 1000000) + t1.getNanos(); 
     long secondTime = (getTimeNoMillis(t2) * 1000000) + t2.getNanos(); 
     long diff = Math.abs(firstTime - secondTime); // diff is in nanos 
     System.out.println(diff); 
     System.out.println(Math.abs(t1.getTime() - t2.getTime())); 
    } 
    private static long getTimeNoMillis(Timestamp t) { 
     return t.getTime() - (t.getNanos()/1000000); 
    } 
} 

Salida:

2009-02-24 10:35:15.56500006 
2009-02-24 10:35:15.59600003 
30999970 
31

Datos 3: Si prefiere algo que devuelve una marca de tiempo, use esto:

public static Timestamp diff(Timestamp t1, Timestamp t2) { 
    long firstTime = (getTimeNoMillis(t1) * 1000000) + t1.getNanos(); 
    long secondTime = (getTimeNoMillis(t2) * 1000000) + t2.getNanos(); 
    long diff = Math.abs(firstTime - secondTime); // diff is in nanoseconds 
    Timestamp ret = new Timestamp(diff/1000000); 
    ret.setNanos((int) (diff % 1000000000)); 
    return ret; 
} 
private static long getTimeNoMillis(Timestamp t) { 
    return t.getTime() - (t.getNanos()/1000000); 
} 

Este código supera las pruebas unitarias.

+0

Para convertir a nanosegundos, necesita multiplicar por 1000000. La pregunta es si llegará a un desbordamiento largo en algún momento. – Richard

+0

@Richard: Sí y sí, parece. –

+0

Acabo de ver la edición de la pregunta. Ay. : P –

1

Sobre la base de código mmyers ...

import java.math.BigInteger; 
import java.sql.Timestamp; 


public class Main 
{ 
    // 1s == 1000ms == 1,000,000us == 1,000,000,000ns (1 billion ns) 
    public final static BigInteger ONE_BILLION = new BigInteger ("1000000000"); 
    public static void main(String[] args) throws InterruptedException 
    { 
     final Timestamp t1; 
     final Timestamp t2; 
     final BigInteger firstTime; 
     final BigInteger secondTime; 
     final BigInteger diffTime; 

     t1 = new Timestamp(System.currentTimeMillis()); 
     Thread.sleep(20); 
     t2 = new Timestamp(System.currentTimeMillis()); 

     System.out.println(t1); 
     System.out.println(t2); 
     firstTime = BigInteger.valueOf(t1.getTime()/1000 * 1000).multiply(ONE_BILLION).add(BigInteger.valueOf(t1.getNanos())); 
     secondTime = BigInteger.valueOf(t2.getTime()/1000 * 1000).multiply(ONE_BILLION).add(BigInteger.valueOf(t2.getNanos())); 
     diffTime = firstTime.subtract(secondTime); 
     System.out.println(firstTime); 
     System.out.println(secondTime); 
     System.out.println(diffTime); 
    } 
} 
+0

+1: Probablemente no sea la solución más rápida posible, pero definitivamente es la más simple de codificar. Sin embargo, intente ejecutar el código con mis pruebas unitarias. Creo que ensuciará los milisegundos tan pronto como nanos% 1000000! = 0. –

+0

Sugerencia de rendimiento: esta solución requiere aproximadamente tres veces más tiempo que mi solución, pero aproximadamente 1/6 del tiempo para codificar. –

Cuestiones relacionadas