2009-02-24 33 views
10

Xin bao gồm các nanos, nếu không nó sẽ là tầm thường:Làm thế nào để tính toán sự khác biệt giữa hai java.sql.Timestamps Java?

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

[EDIT] Tôi muốn kết quả chính xác nhất, vì vậy không đôi; chỉ số nguyên/số học dài. Ngoài ra, kết quả phải dương. Pseudo code:

Timestamp result = abs (t1 - t2); 

Ví dụ:

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

Vâng, mili giây trong java.sql.Timestamp được nhân đôi trong thời gian và mệnh nanos, vì vậy năm 1001 mili giây có nghĩa là 1 giây (1000) và 1 milli nằm trong phần time và phần nanos vì 1 mili giây = 1000000 nano giây). Điều này là nhiều hơn nữa devious hơn nó trông.

Tôi đề xuất không đăng câu trả lời mà không thực sự kiểm tra mã hoặc có sẵn mẫu mã đang hoạt động :)

+0

Vì vậy, bạn có một giải pháp mà bạn sẽ đăng nếu không ai nhận được nó? –

+0

Theo nhận xét trong mã nguồn cho Dấu thời gian, phần millis không thực sự được nhân đôi trong các nano. Thay vào đó, chỉ tối đa giây được lưu trữ trong lớp siêu java.lang.Date, và các nanô cung cấp tất cả thời gian còn lại. – Richard

+0

@mmyers: Tôi đã làm việc trên một nhưng tôi hy vọng rằng ai đó đã có một ví dụ làm việc tiết kiệm bộ não nghèo của tôi ... nhưng tôi nên đoán rằng không ai có khi Google không biến bất cứ điều gì lên nhưng t1.getTime() - t2 .getTime() –

Trả lời

10

Sau một giờ và kiểm tra đơn vị khác nhau, tôi đã đưa ra giải pháp này:

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

Unit tests:

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

Sau nhiều lần thử, tôi không thể lấy mã phiên bản BigInteger của tôi chậm hơn 3 lần so với mã của bạn. Điều này xứng đáng là một upvote. –

+0

Cảm ơn :) Lợi thế của mã BigInt là nó là một dòng đơn (và dễ hiểu hơn). Đó là lý do tại sao tôi đã cho nó một +1. –

3

Trong đơn vị nào? khác biệt của bạn ở trên sẽ cung cấp cho mili giây, Timestamp.nanos() trả về một int, mà sẽ là (phần triệu?) của một phần nghìn giây. Vậy bạn có nghĩa là ví dụ:

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

hoặc tôi đang thiếu gì đó? Một câu hỏi khác là bạn cần mức độ chính xác này? AFAIK JVM không được đảm bảo chính xác ở cấp độ này, tôi không nghĩ rằng nó là vấn đề trừ khi bạn chắc chắn nguồn dữ liệu của bạn là chính xác.

+1

Thiếu hai)) ở cuối. –

+0

Tôi muốn có kết quả chính xác. –

+0

Cảm ơn vì nỗ lực; Tôi đã đăng một giải pháp chính xác nhưng cậu bé, API đó là * mess * –

0

(mã cũ bị loại bỏ để rút ngắn câu trả lời)

EDIT 2: Code mới:

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

Output:

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

Sửa 3: Nếu bạn muốn cái gì đó trả về Dấu thời gian, sử dụng điều này:

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

Mã này vượt qua các bài kiểm tra đơn vị của bạn.

+0

Để chuyển đổi thành nano giây, bạn cần nhân với 1000000. Câu hỏi đặt ra là liệu bạn sẽ nhấn vào một luồng tràn dài tại một số điểm. – Richard

+0

@Richard: Có và có, có vẻ như vậy. –

+0

Chỉ cần xem bản chỉnh sửa cho câu hỏi. Ouch. : P –

1

xây dựng trên mmyers mã ...

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: Có lẽ không phải là giải pháp nhanh nhất có thể nhưng chắc chắn là mã đơn giản nhất. Tuy nhiên, hãy thử chạy mã với các bài kiểm tra đơn vị của tôi. Tôi nghĩ rằng nó sẽ mess up mili giây ngay sau khi nanos% 1000000! = 0. –

+0

gợi ý hiệu suất: Điều này mất khoảng ba lần để chạy như là giải pháp của tôi nhưng khoảng 1/6 thời gian để mã. –

Các vấn đề liên quan