2009-01-17 69 views
17

Tôi thấy thật buồn cười khi Java (hoặc thư viện java.util) không có hàm dựng sẵn để tính toán sự khác biệt về ngày tháng. Tôi muốn trừ một ngày từ một ngày khác để có được thời gian trôi qua giữa chúng. Cách tốt nhất để làm việc này là gì?Tính toán sự khác biệt về ngày tháng trong Java

Tôi biết cách đơn giản là lấy chênh lệch thời gian bằng mili giây và sau đó chuyển đổi thành ngày. Tuy nhiên, tôi muốn biết nếu điều này làm việc trong mọi trường hợp (với tiết kiệm ánh sáng ban ngày, vv).

+2

Xem http://www.xmission.com/~goodhill/dates/deltaDates.html để biết một số thông tin cơ bản. –

+0

Đó là một bài viết hay. Cảm ơn! – Anirudh

+0

@Anirudh Tìm kiếm StackOverflow cho "joda" và thuật ngữ như "span", "Interval", "Duration", "Period". Bạn sẽ tìm thấy nhiều ví dụ với thảo luận. –

Trả lời

6

Tôi biết cách đơn giản là lấy chênh lệch thời gian bằng mili giây và sau đó chuyển đổi thành ngày. Tuy nhiên, tôi muốn biết nếu điều này hoạt động trong mọi trường hợp (với ánh sáng ban ngày lưu, v.v ...).

Nếu thời gian của bạn bắt nguồn từ ngày UTC hoặc chỉ là sự khác biệt giữa hai cuộc gọi đến System.getCurrentTimeMillis() được đo trên cùng một hệ thống, bạn sẽ nhận được một số mili giây hợp lệ là khác biệt, độc lập bất kỳ vấn đề múi giờ nào. (đó là lý do tại sao mọi thứ nên sử dụng UTC như một định dạng lưu trữ - dễ dàng hơn để đi từ UTC-> giờ địa phương, nếu bạn cố gắng đi theo cách khác thì bạn cần lưu múi giờ địa phương cùng với giờ địa phương - hoặc cố gắng suy luận, gack!)

Để biến điều này thành một số ngày, bạn chỉ có thể chia cho 86400000 ... với báo trước rằng thỉnh thoảng thỉnh thoảng có leap second mỗi năm.

8

Java không bị thiếu nhiều, nếu bạn nhìn vào mã nguồn mở: hãy thử Joda-Time.

+3

câu hỏi về Java date ==> câu trả lời đề cập đến Joda! –

+1

Vâng, đó là cách nó hoạt động khi một ngôn ngữ có 2 lớp ngày/giờ bị lỗi. – krosenvold

+0

Tôi nhìn Joda - thật không may, tôi không được phép sử dụng các thư viện không chuẩn: ( – Anirudh

0

Tôi không đồng ý với yêu cầu Java không có cơ chế tính toán sự khác biệt giữa các ngày.

Java được thiết kế để sử dụng toàn cầu. Nó được thiết kế sao cho không có khái niệm về ngày tháng, chỉ có khái niệm "thời gian tính bằng mili giây". Bất kỳ sự giải thích nào về thời gian phổ biến như thời gian và ngày tháng tại một địa điểm cụ thể theo một quy ước cụ thể chỉ là một phép chiếu hoặc một khung nhìn.

Lớp lịch được sử dụng để biến loại thời gian tuyệt đối này thành các ngày. Bạn cũng có thể cộng hoặc trừ các thành phần ngày, nếu bạn thực sự cần. Cách duy nhất để cung cấp sự khác biệt về thành phần giữa hai lần sẽ là Lịch được tạo và cụ thể. Vì vậy, bạn có thể tranh luận rằng thư viện chuẩn không bao gồm một lịch Gregorian đủ thông minh, và tôi đồng ý rằng nó để lại một số mong muốn.

Điều đó đang được nói, có rất nhiều triển khai loại chức năng này, tôi thấy những người khác đã cung cấp các ví dụ.

+0

Tôi đồng ý với bạn về nguyên tắc. Yêu cầu của tôi về Java không có chức năng này được dựa trên thực tế là các ngôn ngữ khác (Ruby, Python, vv) có thực hiện rất đơn giản (và làm việc) để cộng và trừ ngày tháng như một phần của các lớp Date chuẩn. – Anirudh

2

Với thư viện date4j:

int numDaysBetween = oneDate.numDaysFrom(anotherDate); 
1

Có cách đơn giản để thực hiện nó. Chúng ta có thể sử dụng phương thức Calendar.add với vòng lặp. Ví dụ như dưới đây,

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 

Date beginDate = dateFormat.parse("2013-11-29"); 
Date endDate = dateFormat.parse("2013-12-4"); 

Calendar beginCalendar = Calendar.getInstance(); 
beginCalendar.setTime(beginDate); 

Calendar endCalendar = Calendar.getInstance(); 
endCalendar.setTime(endDate); 

Những ngày trừ giữa beginDate và ENDDATE, và mã như dưới đây,

int minusDays = 0; 
while (true) { 
    minusDays++; 

    // Day increasing by 1 
    beginCalendar.add(Calendar.DAY_OF_MONTH, 1); 

    if (dateFormat.format(beginCalendar.getTime()). 
      equals(dateFormat.format(endCalendar).getTime())) { 
    break; 
    } 
} 
System.out.println("The substractation between two days is " + (minusDays + 1)); 

Have Fun! @. @

+0

Tôi đã sử dụng phương pháp này trước đây. Tuy nhiên, thời gian chạy là O (N), trong đó N là số ngày giữa startDate và endDate. Tôi nghi ngờ sử dụng JodaTime sẽ cho kết quả tốt hơn. – jharig23

+0

Đúng, bạn nói đúng. NHƯNG tôi nghĩ rằng O (n) là chấp nhận được đối với một số dự án. Bởi vì tôi không muốn nhập một số lib. Vẫn nhờ lời đề nghị của bạn. –

4

Sử dụng một trong hai Joda thời gian hoặc gói java.time mới trong Java 8.

Cả khuôn khổ sử dụng the Half-Open cách tiếp cận nơi đầu là bao gồm khi kết thúc là độc quyền. Đôi khi được chú ý là [). Đây thường là cách tiếp cận tốt nhất để xác định khoảng thời gian.

java.time

Khung java.time xây dựng vào Java 8 và sau đó có một lớp Period để đại diện cho một khoảng thời gian như một số năm, một số tháng, và một số ngày. Nhưng lớp học này được giới hạn trong cả ngày, không đại diện cho giờ, phút và giây.

Lưu ý rằng chúng tôi chỉ định múi giờ, rất quan trọng để xác định ngày. Ví dụ: một ngày mới xuất hiện sớm hơn trong Paris so với số Montréal.

ZoneId zoneId = ZoneId.of("America/Montreal"); 
LocalDate now = LocalDate.now(zoneId); 
LocalDate then = LocalDate.of(2001, 1, 1); 
Period period = Period.between(then, now); 

Sau đó: 2001-01-01. Bây giờ: 2015-09-07. Thời gian: P14Y8M6D. Ngày: 5362

Trong cả ngày, sau đó Daylight Saving Time (DST) không liên quan.

Nếu bạn muốn đếm tổng số ngày, hãy sử dụng enum ChronoUnit bao gồm một số phương pháp tính toán. Lưu ý các phép tính trả về một thời gian dài.

long days = ChronoUnit.DAYS.between(then, now); // "5362" seen above. 

I have asked về làm một giai đoạn đầy đủ trong java.time, bao gồm giờ, phút, giây. Không thể sử dụng Java 8. Một giải pháp đáng ngạc nhiên khi sử dụng thư viện được nhóm was suggested bởi Meno Hochschild: Sử dụng lớp Duration được tìm thấy trong số javax.xml.datatype package.

Joda-Time

Dưới đây là một số mã ví dụ trong Joda-Time 2.3.

DateTimeZone timeZone = DateTimeZone.forID("Europe/Paris"); 
DateTime start = new DateTime(2014, 1, 2, 3, 4, 5, timeZone); 
DateTime stop = new DateTime(2014, 5, 2, 3, 4, 5, timeZone); 
Period period = new Period(start, stop); 

Calling toString sẽ giúp bạn có một chuỗi đại diện theo mẫu quy định của tiêu chuẩn ISO 8601, PnYnMnDTnHnMnS.

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