2012-04-03 38 views
7

Có cách nào nhanh chóng để tạo cá thể DateTime và đặt phút \ giây \ millis thành 0 không? Tại thời điểm này tôi đang sử dụng đoạn mã sau:Vấn đề về hiệu suất với thời gian joda DateTime.with *()

private DateTime createDateTime(java.util.Date date, org.joda.time.Chronology chronology) { 
    DateTime dateTime = new DateTime(date, chronology); 
    dateTime = dateTime.withMinuteOfHour(0); 
    dateTime = dateTime.withSecondOfMinute(0); 
    dateTime = dateTime.withMillisOfSecond(0); 
    return dateTime; 
} 

Nhưng khi nó gọi về 200.000 lần, dateTime.with *** (0); mất rất nhiều thời gian. Có lẽ có giải pháp chính xác hơn?

Trả lời

8

Có thể như thế này?

// Truncate minutes/seconds/milliseconds from the date's timestamp 
long truncatedTimestamp = date.getTime() - date.getTime() % 3600000; 
DateTime dateTime = new DateTime(truncatedTimestamp, chronology);  

Tại sao điều này nhanh hơn?

  • giải pháp của tôi sử dụng số nguyên số học nhanh (không đáng kể) và 1 unix timestamp bình thường (đắt tiền) trong các nhà xây dựng DateTime
  • giải pháp của bạn sử dụng 1 unix timestamp bình thường (đắt tiền) trong các nhà xây dựng DateTime và 3 normalisations hơn (đắt tiền), mỗi khi bạn thiết lập một số phần ngày để 0
  • giải pháp khác có thể cần ít dòng mã, nhưng khi bạn nhìn vào nguồn JodaTime, họ yêu cầu thậm chí nhiều hơn 3 normalisations (đắt tiền)

Do đó, bạn có thể không thể đánh bại modulo. Như những người khác đã chỉ ra, điều này có thể dẫn đến kết quả không chính xác trong các trường hợp góc rất xa, trong đó giờ không tính 60 giây (ví dụ: do giây nhảy), mặc dù tôi không thấy cách, vì dấu thời gian unix luôn có thể bị cắt bớt không, để bắt đầu một giờ lịch (ví dụ chào mừng).

+0

Không có số giây cố định trong một phút, vì vậy đôi khi điều này sẽ sai. – Dunes

+0

Là số học, đặc biệt là tính toán Modulo nhanh hơn phương pháp 3 bộ? Ngoài ra, date.getTime(), u đã làm điều đó hai lần, do đó, 2 getters và một tính toán, là thực sự nhanh hơn 3 setters? Và kể từ khi anh ta định cư giờ là 0, không nên cũng vậy, 3600000 * 24 – Churk

+0

@Churk: Đừng lo lắng về những điều nhỏ nhặt này. Cái đắt tiền trong phương thức 'with' là số học toàn thời gian. Lưu ý, OP không đặt giờ thành '0' –

5

Chỉ cần thử đoạn code dưới đây - nó trông như phương pháp 1 (của bạn) mất khoảng 320ms trên pc của tôi, vs phương pháp 2 (mỏ) 390ms , so với phương pháp 3 (Lukas's) 15ms, so với phương pháp 4 (MutableDateTime) 310ms ... Bây giờ modulo có thể (?) dẫn đến kết quả không chính xác.

public class Test { 

    private static int NUM_RUN; 

    public static void main(String[] args) { 

     Date date = new Date(); 
     List<Runnable> list = new ArrayList<>(); 

     list.add(method3Withs(date)); 
     list.add(method1With(date)); 
     list.add(methodModulo(date)); 
     list.add(methodMutable(date)); 

     NUM_RUN = 100_000; 
     for (Runnable r : list) { 
      long start = System.nanoTime(); 
      r.run(); 
      long end = System.nanoTime(); 
      System.out.println((end - start)/1000000); 
     } 

     NUM_RUN = 10_000_000; 
     for (Runnable r : list) { 
      long start = System.nanoTime(); 
      r.run(); 
      long end = System.nanoTime(); 
      System.out.println((end - start)/1000000); 
     } 
    } 

    private static Runnable method3Withs(final Date date) { 
     return new Runnable() { 

      @Override 
      public void run() { 
       DateTime d2 = null; 
       for (int i = 0; i < NUM_RUN; i++) { 
        d2 = new DateTime(date); 
        d2 = d2.withMinuteOfHour(0); 
        d2 = d2.withSecondOfMinute(0); 
        d2 = d2.withMillisOfSecond(0); 
       } 
       System.out.println(d2); 
      } 
     }; 
    } 

    private static Runnable method1With(final Date date) { 
     return new Runnable() { 

      @Override 
      public void run() { 
       DateTime d2 = null; 
       for (int i = 0; i < NUM_RUN; i++) { 
        d2 = new DateTime(date); 
        d2 = d2.withTime(d2.getHourOfDay(), 0, 0, 0); 
       } 
       System.out.println(d2); 
      } 
     }; 
    } 
    private static Runnable methodModulo(final Date date) { 
     return new Runnable() { 

      @Override 
      public void run() { 
       DateTime d2 = null; 
       for (int i = 0; i < NUM_RUN; i++) { 
        long truncatedTimestamp = date.getTime() - date.getTime() % 3600000; 
        d2 = new DateTime(truncatedTimestamp); 
       } 
       System.out.println(d2); 
      } 
     }; 
    } 

    private static Runnable methodMutable(final Date date) { 
     return new Runnable() { 

      @Override 
      public void run() { 
       MutableDateTime m = null; 
       for (int i = 0; i < NUM_RUN; i++) { 
        m = new MutableDateTime(date); 
        m.setMinuteOfHour(0); 
        m.setSecondOfMinute(0); 
        m.setMillisOfSecond(0); 
       } 
       System.out.println(m); 
      } 
     }; 
    } 
} 

EDIT
tôi đã làm cho nó 10 triệu chạy sau khi một vòng ấm lên 100.000:

Các modulo phương thức thắng lớn lề, vì vậy nó có vẻ an toàn để nghĩ rằng nó sẽ thực hiện tốt hơn trong hầu hết các tình huống.

+2

eek microbenchmark! http://stackoverflow.com/q/504103/116509 – artbristol

+1

@artbristol Có tôi biết đó là lý do tại sao tôi nhấn mạnh ** trông giống như **;) – assylias

+0

Tham số đầu vào là cho 'java.util.Date', không phải' DateTime' – artbristol

1

Cách sử dụng phương thức withTime() của lớp DateTime, để bạn chỉ phải thực hiện một cuộc gọi?

private DateTime createDateTime(java.util.Date date, org.joda.time.Chronology chronology) { 
    DateTime dateTime = new DateTime(date, chronology); 
    return dateTime.withTime(dateTime.getHourOfDay(), 0, 0, 0); 
} 
+0

Vô tình nó ** có vẻ ** chạy chậm hơn ... – assylias

+0

@assylias Ah vâng, tôi thấy đó là một trong những trường hợp thử nghiệm của bạn. Điều đó thực sự kỳ lạ, đặc biệt nếu bạn nhìn vào mã nguồn của Joda Time để xem chính xác tất cả những phương thức 'with ...()' nào thực hiện. – Jesper

+0

Hoặc có thể do cách tôi thử nghiệm nó là một chút đơn giản! – assylias

3

Phương pháp này dateTime.hourOfDay().roundFloorCopy() nên làm tròn phút, giây và milli bằng không trong một cuộc gọi phương pháp duy nhất (và là cách khuyến cáo nếu hiệu suất không phải là một vấn đề). Tuy nhiên, nó không có khả năng nhanh hơn gọi modulo trên trực tiếp.

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