2009-02-24 9 views
10

Proszę zawierać Nanos, inaczej byłoby trywialne:Jak obliczyć różnicę między dwoma Java java.sql.Timestamps?

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

[EDIT] Chcę najbardziej dokładny wynik, więc nie ma podwójne; tylko liczba całkowita/długa arytmetyczna. Ponadto wynik musi być dodatni. pseudokod:

Timestamp result = abs (t1 - t2); 

Przykłady:

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

Tak milisekund java.sql.Timestamp powtarzają się w czasie i na równi nano tak 1001 milisekund oznacza 1 sekundę (1000) i 1 Milli który znajduje się w części time i części nanos z powodu 1 milisekundy = 1000000 nanosekund). To jest o wiele bardziej przebiegły niż się wydaje.

Proponuję nie pisać odpowiedzi bez faktycznie testowania kodu lub posiadające przykładowy kod gotowy do pracy :)

+0

Tak masz rozwiązanie, które zamierzasz opublikować, jeśli nikt go nie otrzyma? –

+0

Zgodnie z komentarzami w kodzie źródłowym dla datownika, część millis nie jest faktycznie duplikowana w nanosach. Zamiast tego, tylko do sekund sekund są przechowywane w super klasy java.lang.Date, a nanos zapewnia całą resztę czasu. – Richard

+0

@mmyers: Pracowałem nad jednym ale miałem nadzieję, że ktoś miał przykład pracy ratując mój biedny mózg ... ale powinienem był zgadnąć, że nikt nie ma kiedy Google nie zmieniło nic, ale t1.getTime() - t2 .getTime() –

Odpowiedz

10

Po jednej godzinie i różnych testów jednostkowych, wpadłem na to rozwiązanie:

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

testy jednostkowe:

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

Po wielu próbach, nie mogę uzyskać wersji BigInteger mojego kodu mniej niż trzy razy wolniej niż twój kod. To zasługuje na przegraną. –

+0

Dzięki :) Zaletą kodu BigInt jest to, że jest to pojedyncza linia (i łatwiejsza do zrozumienia). Dlatego dałem mu +1. –

3

W jakich jednostkach? twoja różnica powyżej da milisekundy, Timestamp.nanos() zwraca int, które będzie w (milionach?) milisekundy. Czy masz na myśli np.

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

czy czegoś brakuje? Inne pytanie brzmi: czy potrzebujesz tego poziomu precyzji? AFAIK, JVM, nie może być precyzyjny na tym poziomie, nie sądzę, żeby to miało znaczenie, chyba że jesteś pewien, że twoje źródło danych jest tak dokładne.

+1

Brakujące dwa)) na końcu. –

+0

Chciałbym dokładny wynik, proszę. –

+0

Dzięki za wysiłek; Postawiłem dokładne rozwiązanie, ale chłopcze, to API to * bałagan * –

0

(stary kod usuwa skrócić odpowiedź)

EDIT 2: Nowy kod:

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); 
    } 
} 

wyjściowa:

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

Edit 3: Jeśli wolałbym coś, co zwraca znacznik czasu, użyj tego:

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); 
} 

Ten kod przechodzi testy jednostki.

+0

Aby przekonwertować na nanosekundy, należy pomnożyć przez 1000000. Pytanie brzmi, czy w pewnym momencie trafisz na długi przelew. – Richard

+0

@Richard: Tak i tak, wygląda na to. –

+0

Po prostu zobaczyłem edycję na pytanie. Oooo. : P –

1

Opierając się na kodzie 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: Prawdopodobnie nie jest to najszybsze z możliwych rozwiązań, ale zdecydowanie najprostsze do zakodowania. Spróbuj jednak uruchomić kod przy pomocy moich testów jednostkowych. Myślę, że będzie to zepsuć milisekundy, jak tylko nanos% 1000000! = 0. –

+0

Wskazówka dotycząca wydajności: to trwa około trzy razy dłużej niż moje rozwiązanie, ale około 1/6 czasu na kodowanie. –

Powiązane problemy