Rozdiel medzi dvoma dátumami v Jave

1. Prehľad

V tomto rýchlom zápise preskúmame viac možností výpočtu rozdielu medzi dvoma dátumami v Jave.

2. Jadro Java

2.1. Použitím java.util.Date nájsť rozdiel v dňoch

Začnime výpočtom a určením počtu dní medzi týmito dvoma dátumami pomocou základných rozhraní Java API:

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

2.2. Použitím java.time.temporal.ChronoUnit nájsť rozdiel

Time API v Jave 8 predstavuje jednotku dátumu a času, napr. sekúnd alebo dní, pomocou TemporalUnit rozhranie. Každá jednotka poskytuje implementáciu pre metódu s názvom medzi vypočítať čas medzi dvoma dočasnými objektmi z hľadiska konkrétnej jednotky.

Napríklad na výpočet sekúnd medzi dvoma LocalDateTimes:

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

ChronoUnit poskytuje súbor konkrétnych časových jednotiek implementáciou TemporalUnit rozhranie. Veľmi sa to odporúča statický import the ChronoUnitenum hodnoty na dosiahnutie lepšej čitateľnosti:

import statickej java.time.temporal.ChronoUnit.SECONDS; // vynechaný long diff = SECONDS.b Between (now, tenSecondsLater);

Môžeme tiež odovzdať ľubovoľné dva kompatibilné dočasné objekty do medzi metóda, dokonca aj ZonedDateTime.

Čo je super ZonedDateTime je, že výpočet bude fungovať, aj keď sú nastavené na rôzne časové pásma:

@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.b Between (sixMinutesBehind, now); assertEquals (6, rozdiel); } 

2.3. Použitím java.time.temporal.Temporal # until ()

akýkoľvek Dočasný objekt, ako napr LocalDate alebo ZonedDateTime, poskytuje do metóda na výpočet času do iného Dočasný pokiaľ ide o uvedenú jednotku:

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

The Dočasné # do a TemporalUnit # medzi sú dve rôzne API pre rovnakú funkcionalitu.

2.4. Použitím java.time.Duration a java.time.Period

V prostredí Java 8 predstavilo rozhranie Time API dve nové triedy: Trvanie a Obdobie.

Ak chceme vypočítať rozdiel medzi dvoma dátumami a časmi v časovom (hodinovom, minútovom alebo sekundovom) časovom rozmedzí, môžeme použiť Trvanie trieda:

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

Avšak mali by sme si dávať pozor na nástrahu, ak sa pokúsime použiť Obdobie triedy, aby predstavovali rozdiel medzi dvoma dátumami.

Príklad to rýchlo vysvetlí. Vypočítajme koľko dní medzi dvoma dátumami pomocou Obdobie trieda:

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

Ak vykonáme vyššie uvedený test, vyhovie. Môžeme si myslieť Obdobie triedy je vhodné náš problém vyriešiť. Zatiaľ je všetko dobré.

Ak tento spôsob bude fungovať s rozdielom šiestich dní, nebudeme pochybovať, že to bude fungovať aj 60 dní.

Ďalej zmeňme 6 vo vyššie uvedenom teste 60a uvidíte, čo sa stane:

@Test public void givenTwoDatesInJava8_whenUsingPeriodGetDays_thenDoesNotWork () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Obdobie = Obdobie.medzi (aDate, šesťdesiat dníBehind); int diff = Math.abs (period.getDays ()); assertEquals (60, rozdiel); }

Teraz, ak test spustíme znova, uvidíme:

Chyba java.lang.AssertionError: Očakávaná: 60 Skutočná: 29

Ojoj! Prečo Obdobie trieda nahlásiť rozdiel ako 29 dni?

Je to preto, lebo Obdobie trieda predstavuje časovo orientovaný dátum vo formáte „x rokov, y mesiacov a dní“. Keď hovoríme jeho getDays () metóda vráti iba „z dní”Časť.

Preto obdobie objekt v teste vyššie má hodnotu: „0 rokov, 1 mesiac a 29 dní“:

@Test public void givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Obdobie = Obdobie.medzi (aDate, šesťdesiat dníBehind); int years = Math.abs (period.getYears ()); int mesiace = Math.abs (period.getMonths ()); int days = Math.abs (period.getDays ()); assertArrayEquals (new int [] {0, 1, 29}, new int [] {roky, mesiace, dni}); }

Ak chceme vypočítať rozdiel v dňoch pomocou Java 8 Time API, ChronoUnit.DAYS.b Between () najjednoduchší spôsob.

3. Externé knižnice

3.1. JodaTime

Môžeme tiež urobiť relatívne priamu implementáciu s JodaTime:

 joda-time joda-time 2.9.9 

Najnovšiu verziu Joda-time môžete získať z Maven Central.

LocalDate prípad:

@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.daysB Between (now, sixDaysBehind) .getDays ()); assertEquals (6, rozdiel); } 

Podobne s LocalDateTime to je:

@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.minutesB Between (now, sixMinutesBehind) .getMinutes ()); assertEquals (6, rozdiel); } 

3.2. Dátum4J

Date4j tiež poskytuje priamu a jednoduchú implementáciu bez toho, že by sme v tomto prípade museli výslovne uviesť a Časové pásmo.

Začnime so závislosťou Maven:

 com.darwinsys hirondelle-date4j 1.5.1 

Tu je rýchly test pracujúci so štandardom Dátum Čas:

@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, rozdiel); }

4. Záver

V tomto výučbe sme ilustrovali niekoľko spôsobov výpočtu rozdielu medzi dátumami (s časom alebo bez času), a to v bežnej Jave, ako aj pomocou externých knižníc.

Celý zdrojový kód článku je k dispozícii na GitHub.