Forskjellen mellom to datoer i Java

1. Oversikt

I denne raske oppskriften vil vi utforske flere muligheter for å beregne forskjellen mellom to datoer i Java.

2. Core Java

2.1. Ved hjelp av java.util.Date å finne forskjellen i dager

La oss begynne med å bruke Java-API-ene til å beregne og bestemme antall dager mellom de to datoene:

@Test offentlig ugyldighet givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix () kaster ParseException {SimpleDateFormat sdf = ny SimpleDateFormat ("MM / dd / åååå", Språk. ENGLISH); Dato firstDate = sdf.parse ("06/24/2017"); Dato secondDate = sdf.parse ("30.06.2017"); lang diffInMillies = Math.abs (secondDate.getTime () - firstDate.getTime ()); lang diff = TimeUnit.DAYS.convert (diffInMillies, TimeUnit.MILLISECONDS); assertEquals (6, diff); }

2.2. Ved hjelp av java.time.temporal.ChronoUnit å finne forskjellen

Time API i Java 8 representerer en tidsenhet, f.eks. sekunder eller dager, ved hjelp av TemporalUnit grensesnitt. Hver enhet gir en implementering av en metode som heter mellom å beregne hvor lang tid det er mellom to tidsmessige objekter når det gjelder den spesifikke enheten.

For eksempel for å beregne sekunder mellom to LocalDateTimes:

@Test offentlig ugyldighet givenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen () {LocalDateTime nå = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); lang diff = ChronoUnit.SECONDS.between (nå, tenSecondsLater); assertEquals (10, diff); }

ChronoUnit gir et sett med konkrete tidsenheter ved å implementere TemporalUnit grensesnitt. Det anbefales på det sterkeste statisk import de ChronoUnitenum verdier for å oppnå bedre lesbarhet:

importere statisk java.time.temporal.ChronoUnit.SECONDS; // utelatt lang diff = SECONDS.between (nå, tenSecondsLater);

Vi kan også sende to kompatible tidsobjekter til mellom metoden, til og med ZonedDateTime.

Hva er bra med ZonedDateTime er at beregningen vil fungere selv om de er satt til forskjellige tidssoner:

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

2.3. Ved hjelp av java.time.temporal.Temporal # til ()

Noen Temporal objekt, for eksempel LocalDate eller ZonedDateTime, gir en før metode for å beregne tiden til en annen Temporal når det gjelder den spesifiserte enheten:

@Test offentlig ugyldighet givenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen () {LocalDateTime nå = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); lang diff = now.until (tenSecondsLater, ChronoUnit.SECONDS); assertEquals (10, diff); }

De Temporal # til og TemporalUnit # mellom er to forskjellige API-er for samme funksjonalitet.

2.4. Ved hjelp av java.time. varighet og java.time.Period

I Java 8 introduserte Time API to nye klasser: Varighet og Periode.

Hvis vi ønsker å beregne forskjellen mellom to dato-tider i en tidsbasert (time, minutter eller sekunder) tid, kan vi bruke Varighet klasse:

@Test offentlig ugyldighet givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime nå = LocalDateTime.now (); LocalDateTime sixMinutesBehind = now.minusMinutes (6); Varighet varighet = Varighet. Mellom (nå, sixMinutesBehind); lang diff = Math.abs (duration.toMinutes ()); assertEquals (6, diff); }

Derimot, vi bør være forsiktige med en fallgruve hvis vi prøver å bruke Periode klasse for å representere forskjellen mellom to datoer.

Et eksempel vil forklare det raskt. La oss beregne hvor mange dager mellom to datoer som bruker Periode klasse:

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

Hvis vi kjører testen ovenfor, vil den bestå. Vi kan tenke at Periode klassen er praktisk å løse problemet vårt. Så langt så bra.

Hvis denne måten fungerer med en forskjell på seks dager, vil vi ikke tvile på at den også vil fungere i 60 dager.

La oss deretter endre 6 i testen over til 60, og se hva som skjer:

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

Nå, hvis vi kjører testen igjen, ser vi:

java.lang.AssertionError: Forventet: 60 Faktisk: 29

Beklager! Hvorfor gjorde Periode klasse rapporterer forskjellen som 29 dager?

Dette er fordi Periode klasse representerer en datobasert tidsperiode i formatet “x år, y måneder og z dager“. Når vi kaller det getDays () metoden, returnerer den barez dager" del.

derfor periode objektet i testen ovenfor har verdien: “0 år, 1 måned og 29 dager“:

@Test offentlig ugyldighet givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Periode periode = Period.between (aDate, sixtyDaysBehind); int år = Math.abs (period.getYears ()); int måneder = Math.abs (period.getMonths ()); int dager = Math.abs (period.getDays ()); assertArrayEquals (ny int [] {0, 1, 29}, ny int [] {år, måneder, dager}); }

Hvis vi ønsker å beregne forskjellen i dager ved hjelp av Java 8s Time API, er ChronoUnit.DAYS.between () metoden er den enkleste måten.

3. Eksterne biblioteker

3.1. JodaTime

Vi kan også gjøre en relativt grei implementering med JodaTime:

 joda-tid joda-tid 2.9.9 

Du kan få den nyeste versjonen av Joda-time fra Maven Central.

LocalDate sak:

@Test offentlig ugyldig givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDate nå = org.joda.time.LocalDate.now (); org.joda.time.LocalDate sixDaysBehind = now.minusDays (6); lang diff = Math.abs (Days.daysBetween (nå, sixDaysBehind) .getDays ()); assertEquals (6, diff); } 

Tilsvarende med LocalDateTime Det er:

@Test offentlig ugyldighet givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDateTime nå = 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. Dato4J

Dato4j gir også en enkel og enkel implementering, uten å merke seg at vi i dette tilfellet må uttrykke en Tidssone.

La oss starte med Maven-avhengigheten:

 com.darwinsys hirondelle-date4j 1.5.1 

Her er en rask test som arbeider med standarden Dato tid:

@Test offentlig ugyldighet givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix () {DateTime now = DateTime.now (TimeZone.getDefault ()); DateTime sixDaysBehind = now.minusDays (6); lang diff = Math.abs (now.numDaysFrom (sixDaysBehind)); assertEquals (6, diff); }

4. Konklusjon

I denne opplæringen illustrerte vi noen måter å beregne forskjellen mellom datoer (med og uten tid), både i vanlig Java og ved bruk av eksterne biblioteker.

Hele kildekoden til artikkelen er tilgjengelig på GitHub.

$config[zx-auto] not found$config[zx-overlay] not found