Perbedaan Antara Dua Tanggal di Jawa

1. Ikhtisar

Dalam artikel singkat ini, kita akan mempelajari berbagai kemungkinan untuk menghitung perbedaan antara dua tanggal di Jawa.

2. Inti Java

2.1. Menggunakan java.util.Date untuk Menemukan Perbedaan Hari

Mari kita mulai dengan menggunakan API Java inti untuk melakukan penghitungan dan menentukan jumlah hari antara dua tanggal:

@Test public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH); Date firstDate = sdf.parse("06/24/2017"); Date secondDate = sdf.parse("06/30/2017"); long diffInMillies = Math.abs(secondDate.getTime() - firstDate.getTime()); long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS); assertEquals(6, diff); }

2.2. Menggunakan java.time.temporal.ChronoUnit untuk Menemukan Perbedaannya

API Waktu di Java 8 mewakili unit tanggal-waktu, misalnya detik atau hari, menggunakan antarmuka TemporalUnit . Setiap unit menyediakan implementasi untuk metode bernama antara untuk menghitung jumlah waktu antara dua objek temporal dalam satuan tertentu tersebut .

Misalnya, untuk menghitung detik antara dua LocalDateTime :

@Test public void givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen() { LocalDateTime now = LocalDateTime.now(); LocalDateTime tenSecondsLater = now.plusSeconds(10); long diff = ChronoUnit.SECONDS.between(now, tenSecondsLater); assertEquals(10, diff); }

ChronoUnit menyediakan satu set unit waktu konkret dengan mengimplementasikan antarmuka TemporalUnit . Ini sangat dianjurkan untuk impor statis yang ChronoUnit enum nilai-nilai untuk mencapai pembacaan yang lebih baik:

import static java.time.temporal.ChronoUnit.SECONDS; // omitted long diff = SECONDS.between(now, tenSecondsLater);

Selain itu, kita bisa meneruskan dua objek temporal yang kompatibel ke metode antara , bahkan ZonedDateTime .

Yang hebat tentang ZonedDateTime adalah penghitungannya akan berfungsi meskipun disetel ke zona waktu yang berbeda:

@Test public void givenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix() { LocalDateTime ldt = LocalDateTime.now(); ZonedDateTime now = ldt.atZone(ZoneId.of("America/Montreal")); ZonedDateTime sixMinutesBehind = now .withZoneSameInstant(ZoneId.of("Asia/Singapore")) .minusMinutes(6); long diff = ChronoUnit.MINUTES.between(sixMinutesBehind, now); assertEquals(6, diff); } 

2.3. Menggunakan java.time.temporal.Temporal # hingga ()

Setiap Temporal objek, seperti LOCALDATE atau ZonedDateTime, menyediakan sampai metode untuk menghitung jumlah waktu sampai lain Temporal dalam hal unit yang ditentukan:

@Test public void givenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen() { LocalDateTime now = LocalDateTime.now(); LocalDateTime tenSecondsLater = now.plusSeconds(10); long diff = now.until(tenSecondsLater, ChronoUnit.SECONDS); assertEquals(10, diff); }

The Temporal # sampai dan TemporalUnit # antara dua API yang berbeda untuk fungsi yang sama.

2.4. Menggunakan java.time.Duration dan java.time.Period

Di Java 8, Time API memperkenalkan dua kelas baru: Durasi dan Periode .

Jika kita ingin menghitung perbedaan antara dua waktu tanggal dalam jumlah waktu berbasis waktu (jam, menit, atau detik), kita dapat menggunakan kelas Durasi :

@Test public void givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix() { LocalDateTime now = LocalDateTime.now(); LocalDateTime sixMinutesBehind = now.minusMinutes(6); Duration duration = Duration.between(now, sixMinutesBehind); long diff = Math.abs(duration.toMinutes()); assertEquals(6, diff); }

Namun, kita harus waspada terhadap kesalahan jika kita mencoba menggunakan kelas Periode untuk merepresentasikan perbedaan antara dua tanggal .

Sebuah contoh akan menjelaskannya dengan cepat. Mari kita hitung berapa hari antara dua tanggal menggunakan kelas Periode :

@Test public void givenTwoDatesInJava8_whenUsingPeriodGetDays_thenWorks() { LocalDate aDate = LocalDate.of(2020, 9, 11); LocalDate sixDaysBehind = aDate.minusDays(6); Period period = Period.between(aDate, sixDaysBehind); int diff = Math.abs(period.getDays()); assertEquals(6, diff); }

Jika kami menjalankan tes di atas, itu akan lulus. Kita mungkin berpikir bahwa kelas Periode cocok untuk menyelesaikan masalah kita. Sejauh ini bagus.

Jika cara ini berhasil dengan perbedaan enam hari, kami tidak akan meragukan cara ini akan berhasil selama 60 hari juga.

Selanjutnya, mari ubah 6 pada tes di atas menjadi 60 , dan lihat apa yang terjadi:

@Test public void givenTwoDatesInJava8_whenUsingPeriodGetDays_thenDoesNotWork() { LocalDate aDate = LocalDate.of(2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays(60); Period period = Period.between(aDate, sixtyDaysBehind); int diff = Math.abs(period.getDays()); assertEquals(60, diff); }

Sekarang, jika kita menjalankan tes lagi, kita akan melihat:

java.lang.AssertionError: Expected :60 Actual :29

Ups! Mengapa kelas Periode melaporkan perbedaannya sebagai 29 hari?

Ini karena kelas Periode mewakili jumlah waktu berbasis tanggal dalam format " x tahun, y bulan dan z hari ". Saat kita memanggil metode getDays () , ia hanya mengembalikan bagian " z hari ".

Oleh karena itu, objek periode pada pengujian di atas memiliki nilai: " 0 tahun, 1 bulan dan 29 hari ":

@Test public void givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days() { LocalDate aDate = LocalDate.of(2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays(60); Period period = Period.between(aDate, sixtyDaysBehind); int years = Math.abs(period.getYears()); int months = Math.abs(period.getMonths()); int days = Math.abs(period.getDays()); assertArrayEquals(new int[] { 0, 1, 29 }, new int[] { years, months, days }); }

Jika kita ingin menghitung perbedaan hari menggunakan API Waktu Java 8, metode ChronoUnit.DAYS.between () adalah cara yang paling mudah.

3. Perpustakaan Eksternal

3.1. JodaTime

Kami juga dapat melakukan implementasi yang relatif mudah dengan JodaTime :

 joda-time joda-time 2.9.9 

Anda bisa mendapatkan Joda-time versi terbaru dari Maven Central.

Kasus LocalDate :

@Test public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() { org.joda.time.LocalDate now = org.joda.time.LocalDate.now(); org.joda.time.LocalDate sixDaysBehind = now.minusDays(6); long diff = Math.abs(Days.daysBetween(now, sixDaysBehind).getDays()); assertEquals(6, diff); } 

Demikian pula, dengan LocalDateTime :

@Test public void givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix() { org.joda.time.LocalDateTime now = org.joda.time.LocalDateTime.now(); org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes(6); long diff = Math.abs(Minutes.minutesBetween(now, sixMinutesBehind).getMinutes()); assertEquals(6, diff); } 

3.2. Date4J

Date4j juga menyediakan implementasi yang lugas dan sederhana, tanpa catatan bahwa, dalam hal ini, kita perlu menyediakan TimeZone secara eksplisit .

Mari kita mulai dengan ketergantungan Maven:

 com.darwinsys hirondelle-date4j 1.5.1 

Berikut adalah tes cepat yang bekerja dengan DateTime standar :

@Test public void givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix() { DateTime now = DateTime.now(TimeZone.getDefault()); DateTime sixDaysBehind = now.minusDays(6); long diff = Math.abs(now.numDaysFrom(sixDaysBehind)); assertEquals(6, diff); }

4. Kesimpulan

Dalam tutorial ini, kami mengilustrasikan beberapa cara menghitung perbedaan antara tanggal (dengan dan tanpa waktu), baik di Java biasa maupun menggunakan pustaka eksternal.

Kode sumber lengkap artikel tersedia di GitHub.