Razlika između dva datuma u Javi

1. Pregled

U ovom brzom zapisu istražit ćemo više mogućnosti izračuna razlike između dva datuma u Javi.

2. Jezgra Java

2.1. Koristeći java.util.Datum pronaći razliku u danima

Počnimo s korištenjem osnovnih Java API-ja za izračun i određivanje broja dana između dva datuma:

@Test public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix () baca ParseException {SimpleDateFormat sdf = new SimpleDateFormat ("MM / dd / yyyy", Locale.ENGLISH); Datum firstDate = sdf.parse ("24.06.2017."); Datum secondDate = sdf.parse ("30.06.2017."); long diffInMillies = Math.abs (secondDate.getTime () - firstDate.getTime ()); long diff = TimeUnit.DAYS.convert (diffInMillies, TimeUnit.MILLISECONDS); assertEquals (6, razlika); }

2.2. Koristeći java.time.temporal.ChronoUnit pronaći razliku

API vremena u Javi 8 predstavlja jedinicu datuma i vremena, na pr. sekunde ili dana, koristeći TemporalUnit sučelje. Svaka jedinica pruža implementaciju za imenovanu metodu između kako bi se izračunala količina vremena između dva vremenita objekta u smislu te specifične jedinice.

Na primjer, kako bi se izračunale sekunde između dvije LocalDateTimes:

@Test javna praznina givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen () {LocalDateTime sada = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); duga razlika = ChronoUnit.SECONDS.između (sada, desetSekundiKasnije); assertEquals (10, razlika); }

ChronoUnit pruža skup konkretnih vremenskih jedinica primjenom TemporalUnit sučelje. To je toplo preporučljivo statički uvoz the ChronoUnitnabrajanje vrijednosti za postizanje bolje čitljivosti:

uvoz statičke java.time.temporal.ChronoUnit.SECONDS; // izostavljeno long diff = SECONDS.between (now, tenSecondsLater);

Također, možemo proslijediti bilo koja dva kompatibilna privremena objekta na između metoda, čak i ZonedDateTime.

Što je super ZonedDateTime jest da će izračun funkcionirati čak i ako su postavljeni na različite vremenske zone:

@Test javna praznina givenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime ldt = LocalDateTime.now (); ZonedDateTime sada = ldt.atZone (ZoneId.of ("America / Montreal")); ZonedDateTime sixMinutesBehind = sada .withZoneSameInstant (ZoneId.of ("Asia / Singapore")) .minusMinutes (6); duga razlika = ChronoUnit.MINUTES.između (sixMinutesBehind, now); assertEquals (6, razlika); } 

2.3. Koristeći java.time.temporal.Temporal # dok ()

Bilo koji Vremenski objekt, kao što je LocalDate ili ZonedDateTime, pruža an do metoda za izračunavanje vremena do drugog Vremenski u smislu navedene jedinice:

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

The Privremeni # do i TemporalUnit # između dva su različita API-ja za istu funkcionalnost.

2.4. Koristeći java.time.Trajanje i java.time.Period

U Javi 8, Time API predstavio je dvije nove klase: Trajanje i Razdoblje.

Ako želimo izračunati razliku između dva datuma i vremena u vremenu (satu, minutama ili sekundama), možemo koristiti Trajanje razred:

@Test javna praznina givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime sada = LocalDateTime.now (); LocalDateTime sixMinutesBehind = now.minusMinutes (6); Trajanje trajanja = Trajanje.između (sada, šestMinuta iza); duga razlika = Math.abs (duration.toMinutes ()); assertEquals (6, razlika); }

Međutim, trebali bismo se čuvati zamke ako pokušamo koristiti Razdoblje razred koji predstavlja razliku između dva datuma.

Primjer će to brzo objasniti. Izračunajmo koliko dana između dva datuma pomoću Razdoblje razred:

@Test javna praznina givenTwoDatesInJava8_whenUsingPeriodGetDays_thenWorks () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixDaysBehind = aDate.minusDays (6); Razdoblje razdoblja = Razdoblje između (aDate, sixDaysBehind); int diff = Math.abs (period.getDays ()); assertEquals (6, razlika); }

Ako pokrenemo gornji test, proći će. Možda mislimo na Razdoblje klase prikladno je riješiti naš problem. Zasada je dobro.

Ako ovaj način radi s razlikom od šest dana, nećemo sumnjati da će raditi i 60 dana.

Dalje, promijenimo 6 u gornjem testu do 60, i pogledajte što će se dogoditi:

@Test javna praznina givenTwoDatesInJava8_whenUsingPeriodGetDays_thenDoesNotWork () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Razdoblje razdoblja = Razdoblje između (aDate, sixtyDaysBehind); int diff = Math.abs (period.getDays ()); assertEquals (60, razlika); }

Sada, ako ponovo pokrenemo test, vidjet ćemo:

java.lang.AssertionError: Očekivano: 60 Stvarno: 29

Ups! Zašto je Razdoblje razred prijavi razliku kao 29 dana?

To je zato što Razdoblje klasa predstavlja vremensko vrijeme temeljeno na datumu u formatu „x godina, y mjeseci i z dana“. Kad ga nazovemo getDays () metoda, vraća samo "z dana" dio.

Stoga je razdoblje objekt u gornjem testu ima vrijednost: “0 godina, 1 mjesec i 29 dana“:

@Test javna praznina givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Razdoblje razdoblja = Razdoblje između (aDate, sixtyDaysBehind); int godina = Math.abs (period.getYears ()); int mjeseci = Math.abs (period.getMonths ()); int dana = Math.abs (period.getDays ()); assertArrayEquals (novi int [] {0, 1, 29}, novi int [] {godine, mjeseci, dani}); }

Ako želimo izračunati razliku u danima koristeći Java 8's Time API, ChronoUnit.DAYS.be Between () metoda je najjednostavniji način.

3. Vanjske knjižnice

3.1. JodaTime

Također možemo napraviti relativno jednostavnu implementaciju s JodaTime:

 joda-vrijeme joda-vrijeme 2.9.9 

Najnoviju verziju Joda-time možete dobiti od Maven Central.

LocalDate slučaj:

@Test javna praznina 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 (sada, sixDaysBehind) .getDays ()); assertEquals (6, razlika); } 

Slično tome, s LocalDateTime to je:

@Test javna praznina givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDateTime now = org.joda.time.LocalDateTime.now (); org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes (6); duga razlika = Math.abs (Minutes.minutesBetween (sada, sixMinutesBehind) .getMinutes ()); assertEquals (6, razlika); } 

3.2. Datum4J

Datum4j također pruža jednostavnu i jednostavnu provedbu, bez napomene da, u ovom slučaju, moramo izričito navesti a Vremenska zona.

Počnimo s ovisnošću o Mavenu:

 com.darwinsys hirondelle-date4j 1.5.1 

Evo kratkog testa koji radi sa standardom Datum vrijeme:

@Test javna praznina givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix () {DateTime sada = DateTime.now (TimeZone.getDefault ()); DateTime sixDaysBehind = now.minusDays (6); duga razlika = Math.abs (now.numDaysFrom (sixDaysBehind)); assertEquals (6, razlika); }

4. Zaključak

U ovom smo uputstvu ilustrirali nekoliko načina izračunavanja razlike između datuma (s vremenom i bez vremena), kako na običnoj Javi, tako i pomoću vanjskih knjižnica.

Cjeloviti izvorni kôd članka dostupan je na GitHubu.