2017-11-21 24 views
5

Tôi có một số mã sử dụng đối tượng Date làm tên của tệp để có tên tệp riêng biệt mỗi lần nhưng điều lạ là đối tượng Date mới cho ra toString() cho mỗi vòng lặp lặp lại. Ý tôi là, như sau:Đối tượng Date Date() mới có cùng giá trị

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); 
String fileName = sdf.format((d = new Date())) + ".jpg"; 

Log.d("Date", d.toString()); 

được thực hiện theo vòng lặp.

Lưu ý phụ: Vì điều này liên quan đến Java API, tôi chưa gắn thẻ câu hỏi đó là của Android nhưng hệ điều hành thực thi mã này là Android.

AFAIK, new Date() sử dụng System.currentTimeMilis() làm giá trị init, lý do cho hành vi bất thường này là gì?

+3

Java 8 giới thiệu các API mới cho Date and Time. Bạn có thể xem nhanh tại đây: http://www.baeldung.com/java-8-date-time-intro – Touniouk

+1

bạn phải sử dụng milli giây và nếu bạn đang sử dụng các chủ đề sử dụng nano giây – shareef

+2

Bạn có thời gian chờ là vài giây. Bạn có chắc chắn mã không được thực thi trong cùng một giây với mili giây chênh lệch không ?. Tôi sẽ khuyên bạn nên sử dụng System.currentTimeMillis() cho một phần duy nhất của tên tệp. –

Trả lời

5

Bạn định dạng thời gian là yyyyMMdd_HHmmss, nhưng việc chạy vòng lặp chỉ cần một phần nghìn giây, do đó hãy sử dụng yyyyMMdd_HHmmssSSS để có thời gian chính xác hơn. Khi Jon Skeet đề cập đến trong bình luận của mình, chạy vòng lặp thậm chí có thể mất ít hơn một phần nghìn giây (tùy thuộc vào công việc bạn thực hiện), vì vậy bạn cũng có thể gặp vấn đề với giải pháp này!

+2

Rất có thể cho một vòng lặp chạy nhiều lần trong một phần nghìn giây, tất nhiên. Tôi nghĩ rằng nó đáng nói đến điều này trong câu trả lời. –

+0

@Sergej Am xin lỗi, có xác suất sai trên giả định của tôi, tôi đã xóa nhận xét của tôi trước – shareef

+0

không có vấn đề ;-) – Sergej

0

Java trong vòng lặp là nhanh hơn một giây nó sẽ ở lại cùng để đảm bảo luôn luôn độc đáo đặc biệt đa luồng chức năng của nó.

Sử dụng somthing như thế này

SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss:SSSSSSS"); 

Một số gợi ý để bạn wont đi vào nhiều rắc rối debug

printDate("dd.MM.yyyy HH:mm:ss.SSS");//02.05.2010 21:45:58.073 
    printDate("dd.MM.yyyy HH:mm:ss.SSSSSS");//02.05.2010 21:45:58.000073 
    printDate("dd.MM.yyyy HH:mm:ss.SSS'000'");//02.05.2010 21:45:58.073000 
    printDate("dd.MM.yyyy HH:mm:ss.'000000'");//02.05.2010 21:45:58.000000 

    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSS");//good 
    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSSSSS");//good 
    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSS'000'");//bad 
    tryToParseDate("dd.MM.yyyy HH:mm:ss.'000000'");//good 

tham khảo:

@slartidan trả lời

String-Date conversion with nanoseconds

Như Khuyến nghị khi tôi phải đối mặt với tình trạng này:

1)Nếu đang gọi từ S3 AWS

file nó nên được đặt tên như là duy nhất lúc bắt đầu của tập tin tên nó sẽ làm băm và tìm kiếm khá nhanh. như từ các thực hành tốt nhất của AWS S3 để tối ưu hóa.

public static String genarateFileName(String name) { 
     StringBuilder sb = new StringBuilder(name); 
     sb.insert(0, IdUtil.getUniqueUuid());in short to increase performance of S3 put and get etc..) 
     if (sb.lastIndexOf(".") != -1) { 
      sb.insert(sb.lastIndexOf("."), "_" + System.nanoTime()); 
     } else { 
      sb.append("_").append(System.nanoTime()); 
     } 

     return sb.toString(); 
    } 

2)Để tạo nano ngẫu nhiên

public static String getUniqueUuid() { 
     int rand = (int) (Math.random() * 100); 
     return Integer.toHexString(rand) + Long.toHexString(java.lang.System.nanoTime()); 
    } 

3) tôi sử dụng cả hai nano ngẫu nhiên với kiểm tra chuỗi ngẫu nhiên dưới đây tạo ra chuỗi ngẫu nhiên của một số chiều dài

/** 
    * Generate a random uuid of the specified length. Example: uuid(15) returns 
    * "VcydxgltxrVZSTV" 
    * 
    * @param len the desired number of characters 
    * @return 
    */ 
    public static String uuid(int len) { 
     return uuid(len, CHARS.length); 
    } 

    /** 
    * Generate a random uuid of the specified length, and radix. Examples: <ul> 
    * <li>uuid(8, 2) returns "01001010" (8 character ID, base=2) <li>uuid(8, 
    * 10) returns "47473046" (8 character ID, base=10) <li>uuid(8, 16) returns 
    * "098F4D35" (8 character ID, base=16) </ul> 
    * 
    * @param len the desired number of characters 
    * @param radix the number of allowable values for each character (must be 
    * <= 62) 
    * @return 
    */ 
    public static String uuid(int len, int radix) { 
     if (radix > CHARS.length) { 
      throw new IllegalArgumentException(); 
     } 
     char[] uuid = new char[len]; 
     // Compact form 
     for (int i = 0; i < len; i++) { 
      uuid[i] = CHARS[(int) (Math.random() * radix)]; 
     } 
     return new String(uuid); 
    } 
+1

Sử dụng 'SimpleDateFormat' bạn sẽ không thể định dạng chính xác hơn mili giây, vì đó là độ chính xác của 'java.util.Date'. Ngoài ra, bạn đã có được độ chính xác của đồng hồ hệ thống để xem xét, có thể trả về cùng giá trị cho các khối 15ms trong một số trường hợp. Về cơ bản, nếu vòng lặp này đang chạy nhanh, bạn không nên dựa vào đồng hồ hệ thống cho tính duy nhất. –

+0

@JonSkeet đúng thats lý do tại sao tôi sử dụng cả hai kiểm tra thực hành được đề nghị của tôi, 3) Tôi sử dụng cả hai ngẫu nhiên nano với chuỗi ngẫu nhiên kiểm tra dưới đây tạo ra chuỗi ngẫu nhiên của một số chiều dài và cho tôi thức ăn của bạn trở lại tôi sẽ đánh giá cao nó. – shareef

+1

Ngoài những gì @JonSkeet đã nói, sử dụng 6 hoặc 7 vốn 'S' trong chuỗi mẫu định dạng chỉ dẫn đến hiển thị không chính xác mili giây.Ví dụ của bạn được in dưới dạng cả hai '58.073' và' 58.000073', đây không phải là số giống nhau. Cái trước là đúng, cái sau không chính xác. Đối với tính duy nhất, điều đó không quan trọng, nhưng có khả năng một ngày nào đó ai đó sẽ hiểu điều này như một dấu thời gian. –

3

java.time

Cách tiếp cận hiện đại sử dụng các lớp java.time.

Lớp Instant đại diện cho một điểm trên dòng thời gian có độ phân giải nano giây. Lệnh Instant.now nắm bắt thời điểm hiện tại tính bằng mili giây trong Java 8 và tính bằng micro giây trong Java 9 (hoặc có thể tốt hơn).

Thay thế các ký tự dấu hai chấm để tương thích với macOS.

String filename = Instant.now().toString().replace(":" , "-") + ".jpeg" ; 

Lưu ý rằng thậm chí với mili giây hoặc độ phân giải micro giây, bạn vẫn có thể gặp phải xung đột nếu chạy mã ngắn trên lõi nhanh. Tôi đề nghị sử dụng UUID để loại bỏ rủi ro như vậy.

UUID

Nếu bạn chỉ muốn tên tập tin duy nhất mà không thực sự cần phải đại diện cho thời điểm hiện tại trong tên, sau đó sử dụng một giá trị UUID thay vì một ngày thời gian.

Lớp UUID có thể tạo ra một số phiên bản như Version 4 (chủ yếu là ngẫu nhiên):

String filename = UUID.randomUUID() + ".jpeg" ; 
Các vấn đề liên quan