2011-04-30 54 views
6

java.sql.Timestamp constructor đi như thế này:java.sql.Timestamp cách lưu trữ nano giây

public Timestamp(long time) { 
    super((time/1000)*1000); 
    nanos = (int)((time%1000) * 1000000); 
    if (nanos < 0) { 
     nanos = 1000000000 + nanos;  
     super.setTime(((time/1000)-1)*1000); 
    } 
} 

Nó về cơ bản chấp nhận thời gian trong một phần nghìn giây và sau đó trích xuất 3 chữ số cuối cùng và làm cho nó Nanos. Vì vậy, đối với một giá trị mili giây là 1304135631 , tôi nhận được Dấu thời gian.getnanos() là . Đây là tính toán đơn giản (thêm 6 số 0 ở cuối) ... dường như không tối ưu.

Cách tốt hơn có thể là trình tạo dấu thời gian chấp nhận thời gian tính bằng nano giây và sau đó tính giá trị nano giây.

Nếu bạn chạy chương trình dưới đây, bạn sẽ thấy sự khác biệt giữa nano giây thực tế và một giây được trả về theo cách Timestamp tính toán nanosecod.

long a = System.currentTimeMillis(); 
    for(;;){ 
     long b = System.currentTimeMillis(); 
     Timestamp tm = new Timestamp(System.currentTimeMillis()); 
     System.out.println(tm.getTime()); 
     System.out.println(tm.getNanos()); 
     System.out.println("This is actual nanos" + System.nanoTime()%1000000000); 
     System.out.println("--------------------------"); 
     if(b-a >= 1) 
      break; 
    } 

Vì vậy, tất cả các cuộc thảo luận về Dấu thời gian cho biết lưu trữ thời gian lên đến nano giây, có vẻ không chính xác .. Phải không?

Trả lời

6

Thời gian tính bằng milis không đại diện cho thời gian trong nanô. Chính xác hơn nó đơn giản là không thể. Bạn đang sử dụng Timestamp#setNanos() để thiết lập các nanos thực.

long timeInMillis = System.currentTimeMillis(); 
long timeInNanos = System.nanoTime(); 

Timestamp timestamp = new Timestamp(timeInMillis); 
timestamp.setNanos((int) (timeInNanos % 1000000000)); 

// ... 
+1

Có .. Điều này chắc chắn sẽ hoạt động. Vì vậy, để làm cho Dấu thời gian thực sự lưu trữ các nanô, nó phải là quá trình hai bước. Bit lúng túng, thay vào đó một Constructor chấp nhận nanos (từ ngày 1 tháng 1 năm 1970) sẽ là một giải pháp tốt hơn. – Vicky

+1

Không có điều này không an toàn! Nó kết thúc tốt đẹp! Vấn đề là 'currentTimeMillis' và' nanoTime' có thể không đồng ý với độ phân giải lớn hơn. ví dụ. 'nanoTime' trả về giá trị 12: 06: 30.9999, 12:06: ** 31 ** .1111 nhưng' currentTimeMillis' trả về 12: 06: 30.666 12:06: ** 30 ** .777, sau đó sử dụng mã ở trên để khởi tạo dấu thời gian sẽ dẫn đến dấu thời gian 12: 06: 30,9999, 12:06: ** 30 ** .1111. Một cách riêng biệt, nhận xét của @Vicky, bạn sẽ khởi tạo một dấu thời gian trước năm 1970 như thế nào? – Luciano

+0

Đúng là thiết lập nano giây phải được đặt riêng, nhưng sử dụng 'System # nanoTime()' như thế này là không chính xác. Tài liệu API cho 'System # nanoTime()' nói: "Phương pháp này chỉ có thể được sử dụng để đo thời gian trôi qua và không liên quan đến bất kỳ khái niệm nào khác về hệ thống hoặc đồng hồ treo tường.Giá trị được trả về đại diện cho nano giây kể từ thời điểm cố định nhưng tùy ý (có lẽ trong tương lai, vì vậy các giá trị có thể âm). (Xem http://download.oracle.com/javase/6/docs/api/java/lang/System .html # nanoTime% 28% 29) –

0

Mặc dù nó là một bài cũ, tôi muốn nói thêm rằng các tài liệu của Timestamp làm nhà nước mà nó "giữ giây phân đoạn bằng cách cho phép các đặc điểm kỹ thuật của giây phân đoạn với một độ chính xác của nanaoseconds". Phần khó hiểu là "giữ". Điều này có vẻ khó hiểu lúc đầu nhưng nếu hiểu đúng, nó thực sự không nói rằng nó giữ nanaoseconds giá trị. Nó nói rằng nó "giữ" giá trị phân đoạn và cho phép nó là một "độ chính xác" của nano giây. Độ chính xác phải được hiểu theo cách biểu diễn trong tổng số chữ số. Vì vậy, về cơ bản nó có nghĩa là phần thực sự là phân đoạn (vẫn là mili giây) nhưng được nhân với 1000000 để biểu diễn nó dưới dạng nano giây.

Câu trả lời được chấp nhận (bởi BaluC hữu ích bao giờ) tổng hợp nó một cách độc đáo.

0

Tôi thích việc triển khai OpenJPA của TimestampHelper. Nó sử dụng các trình khởi tạo tĩnh để theo dõi các nano giây trôi qua giữa các cuộc gọi để tạo dấu thời gian.

1

Kể từ khi giới thiệu java.time.*, có phương pháp nhà máy mới ở java.sql.Timestamp: Timestamp.from(Instant.now()) sẽ thực hiện công việc (với độ chính xác nano giây). Ngoài ra còn có Timestamp.toInstant() để chuyển đổi theo cách khác.

+0

Java 8 cung cấp ['LocalDateTime.now()'] (https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#now -) ... Hoặc nếu <8, sử dụng 'System.nanoTime()' để lấy dấu thời gian hiện tại .... – KarelG

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