2010-09-27 44 views
264

Làm cách nào để tìm sự khác biệt trong Số ngày giữa hai trường hợp Joda-TimeDateTime? Với ‘sự khác biệt trong những ngày’ tôi muốn nói nếu bắt đầu vào Thứ Hai và kết thúc vào Thứ Ba, tôi dự kiến ​​giá trị trả lại là 1 bất kể giờ/phút/giây của ngày bắt đầu và ngày kết thúc.Số ngày giữa hai ngày trong Joda-Time

Days.daysBetween(start, end).getDays() cho tôi 0 nếu bắt đầu vào buổi tối và kết thúc vào buổi sáng.

Tôi cũng gặp vấn đề tương tự với các trường ngày tháng khác vì vậy tôi đã hy vọng sẽ có một cách chung chung để 'bỏ qua' các trường có ý nghĩa kém hơn.

Nói cách khác, các tháng trong khoảng từ tháng 2 đến ngày 4 tháng 3 cũng sẽ là 1, cũng như thời gian từ 14:45 đến 15:12. Tuy nhiên sự khác biệt giờ 14:01-14:55 sẽ là 0.

Trả lời

318

Khó chịu, câu trả lời withTimeAtStartOfDay là sai, nhưng thỉnh thoảng. Bạn muốn:

Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays() 

Nó chỉ ra rằng "nửa đêm/bắt đầu ngày" đôi khi có nghĩa là 1:00 (tiết kiệm ánh sáng ban ngày xảy ra theo cách này ở một số nơi), trong đó Days.daysBetween không xử lý đúng cách.

// 5am on the 20th to 1pm on the 21st, October 2013, Brazil 
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo"); 
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL); 
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL); 
System.out.println(daysBetween(start.withTimeAtStartOfDay(), 
           end.withTimeAtStartOfDay()).getDays()); 
// prints 0 
System.out.println(daysBetween(start.toLocalDate(), 
           end.toLocalDate()).getDays()); 
// prints 1 

Đi qua một số LocalDate tránh toàn bộ vấn đề.

+0

Bạn có thể cung cấp một trường hợp mẫu với dữ liệu cụ thể mà bạn nghĩ ['Days.daysBetween'] (http://www.joda.org/joda-time/apidocs/org/joda/time/Days.html#daysBetween-org .joda.time.ReadableInstant-org.joda.time.ReadableInstant-) không chính xác? –

+2

@BasilBourque - Ví dụ đã có trong câu trả lời của tôi. –

+0

Khi bạn nói để sử dụng 'Instant', bạn không chỉ nói về' start.toInstant() ', phải không? –

79

bạn có thể sử dụng LocalDate:

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays() 
+0

Thưa ông, với tham chiếu tới [post] này (http://stackoverflow.com/q/17665921/1031945) phương thức 'toDateMidnight()' từ kiểu DateTime không còn được dùng nữa. –

+2

cập nhật ........ – Bozho

+0

Tại sao lại sử dụng 'LocalDate (ngày) mới' trên 'date.toLocalDate()'? – SARose

178

Days Lớp

Sử dụng lớp Days với phương pháp withTimeAtStartOfDay nên làm việc:

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay()).getDays() 
+1

cảm ơn! Tôi đã cố gắng để đạt được hành vi của android.text.format.DateUtils.getRelativeTimeSpanString() với joda và điều này thực sự hữu ích. –

+1

Thưa ông, với tham chiếu đến [post] này (http://stackoverflow.com/q/17665921/1031945) phương thức 'toDateMidnight()' từ kiểu DateTime bị phản đối. –

+2

Bây giờ bạn nên sử dụng .withTimeAtStartOfDay() thay vì .toDateMidnight() – bgolson

-10
public static int getDifferenceIndays(long timestamp1, long timestamp2) { 
    final int SECONDS = 60; 
    final int MINUTES = 60; 
    final int HOURS = 24; 
    final int MILLIES = 1000; 
    long temp; 
    if (timestamp1 < timestamp2) { 
     temp = timestamp1; 
     timestamp1 = timestamp2; 
     timestamp2 = temp; 
    } 
    Calendar startDate = Calendar.getInstance(TimeZone.getDefault()); 
    Calendar endDate = Calendar.getInstance(TimeZone.getDefault()); 
    endDate.setTimeInMillis(timestamp1); 
    startDate.setTimeInMillis(timestamp2); 
    if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) { 
     int day1 = endDate.get(Calendar.DAY_OF_MONTH); 
     int day2 = startDate.get(Calendar.DAY_OF_MONTH); 
     if (day1 == day2) { 
      return 0; 
     } else { 
      return 1; 
     } 
    } 
    int diffDays = 0; 
    startDate.add(Calendar.DAY_OF_MONTH, diffDays); 
    while (startDate.before(endDate)) { 
     startDate.add(Calendar.DAY_OF_MONTH, 1); 
     diffDays++; 
    } 
    return diffDays; 
} 
+1

câu hỏi là cụ thể tìm kiếm thời gian joda. – kapad

2

Câu trả lời được chấp nhận xây dựng hai đối tượng LocalDate, khá tốn kém nếu bạn đang đọc nhiều dữ liệu. tôi sử dụng này:

public static int getDaysBetween(DateTime earlier, DateTime later) 
    { 
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis()); 
    } 

Bằng cách gọi getMillis() bạn sử dụng đã tồn tại biến.
MILLISECONDS.toDays() sau đó, sử dụng phép tính số học đơn giản, không tạo bất kỳ đối tượng nào.

+1

Câu trả lời này chỉ hoạt động nếu định nghĩa ‘ngày’ của bạn chính xác 24 giờ mà không tính đến múi giờ và ngày tháng. Nếu có, hãy sử dụng phương pháp này. Nếu không, hãy xem các câu trả lời khác giải quyết các múi giờ. –

+0

@BasilBourque, bạn nói đúng, tôi sẽ đi một giải pháp dựa trên tính toán số học thay vì xây dựng các đối tượng đắt tiền cho mỗi cuộc gọi phương pháp, có nhiều hương vị ngoài đó để tính toán, nếu bạn đang đọc đầu vào từ trang web , có thể là ok, nhưng nếu bạn đang xử lý một tệp nhật ký với hàng trăm nghìn dòng, điều này chỉ làm cho nó rất chậm – JBoy

+1

Java sẽ tối ưu hóa phân bổ đối tượng nếu vòng lặp của bạn là nóng. Xem http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis –

4

tl; dr

java.time.temporal.ChronoUnit.DAYS.between( 
    earlier.truncatedTo(ChronoUnit.DAYS) , 
    later.truncatedTo(ChronoUnit.DAYS) 
) 

... hoặc ...

java.time.temporal.ChronoUnit.HOURS.between( 
    earlier.truncatedTo(ChronoUnit.HOURS) , 
    later.truncatedTo(ChronoUnit.HOURS) 
) 

java.time

FYI, dự án Joda-Time hiện đang ở maintenance mode, với đội ngũ tư vấn chuyển đổi sang các java.time lớp .

Tương đương với Joda-Time DateTimeZonedDateTime.

ZoneId z = ZoneId.of("Pacific/Auckland") ; 
ZonedDateTime now = ZonedDateTime.now(z) ; 

Dường như bạn muốn đếm ngày theo ngày, có nghĩa là bạn muốn bỏ qua thời gian trong ngày. Ví dụ: bắt đầu một phút trước nửa đêm và kết thúc một phút sau nửa đêm sẽ dẫn đến một ngày. Đối với hành vi này, hãy trích xuất một số LocalDate từ số ZonedDateTime của bạn. Lớp LocalDate đại diện cho giá trị chỉ ngày mà không có thời gian trong ngày và không có múi giờ.

LocalDate localDateStart = zdtStart.toLocalDate() ; 
LocalDate localDateStop = zdtStop.toLocalDate() ; 

Sử dụng ChronoUnit enum để tính toán ngày trôi qua, đơn vị khác.

long days = ChronoUnit.DAYS.between(localDateStart , localDateStop) ; 

Truncate

Đối với bạn hỏi về một cách tổng quát hơn để làm đếm này, nơi bạn quan tâm đồng bằng sông giờ như giờ-of-the-đồng hồ chứ không phải giờ hoàn chỉnh như nhịp-of- thời gian sáu mươi phút, sử dụng phương thức truncatedTo.

Đây là ví dụ của bạn từ 14:45 đến 15:12 cùng ngày.

ZoneId z = ZoneId.of("America/Montreal"); 
ZonedDateTime start = ZonedDateTime.of(2017 , 1 , 17 , 14 , 45 , 0 , 0 , z); 
ZonedDateTime stop = ZonedDateTime.of(2017 , 1 , 17 , 15 , 12 , 0 , 0 , z); 

long hours = ChronoUnit.HOURS.between(start.truncatedTo(ChronoUnit.HOURS) , stop.truncatedTo(ChronoUnit.HOURS)); 

Đối với một số ngày theo ngày, cắt xén để ChronoUnit.DAYS. Dưới đây là ví dụ về sau nửa đêm từ năm phút trước năm phút sau, trong những ngày đã qua là 1.

ZoneId z = ZoneId.of("America/Montreal"); 
ZonedDateTime start = ZonedDateTime.of(2017 , 1 , 17 , 23 , 55 , 0 , 0 , z); 
ZonedDateTime stop = ZonedDateTime.of(2017 , 1 , 18 , 00 , 05 , 0 , 0 , z); 

long days = ChronoUnit.DAYS.between(start.truncatedTo(ChronoUnit.DAYS) , stop.truncatedTo(ChronoUnit.DAYS)); 

Về java.time

Khung java.time được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp học ngày giờ legacy phiền hà cũ như java.util.Date, Calendar, & SimpleDateFormat.

Dự án Joda-Time, hiện đang ở maintenance mode, khuyên di chuyển đến các lớp java.time.

Để tìm hiểu thêm, hãy xem Oracle Tutorial. Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310.

Nơi lấy các lớp java.time?

Dự án mở rộng ThreeTen-Extra java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho những bổ sung có thể có trong tương lai vào java.time. Bạn có thể tìm thấy một số lớp học hữu ích tại đây như Interval, YearWeek, YearQuartermore.

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