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.