Verschil tussen twee datums in Java

1. Overzicht

In dit korte artikel zullen we meerdere mogelijkheden onderzoeken om het verschil tussen twee datums in Java te berekenen.

2. Core Java

2.1. Gebruik makend van java.util.Date om het verschil in dagen te vinden

Laten we beginnen met het gebruik van de Java-kern-API's om de berekening uit te voeren en het aantal dagen tussen de twee datums te bepalen:

@Test openbare ongeldig gegevenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix () gooit ParseException {SimpleDateFormat sdf = nieuwe SimpleDateFormat ("MM / dd / jjjj", Locale.ENGLISH); Datum firstDate = sdf.parse ("24-06-2017"); Datum secondDate = sdf.parse ("30/06/2017"); lange diffInMillies = Math.abs (secondDate.getTime () - firstDate.getTime ()); lange diff = TimeUnit.DAYS.convert (diffInMillies, TimeUnit.MILLISECONDS); assertEquals (6, diff); }

2.2. Gebruik makend van java.time.temporal.ChronoUnit om het verschil te vinden

De Time API in Java 8 vertegenwoordigt een eenheid van datum-tijd, bijv. seconden of dagen, met TemporalUnit koppel. Elke eenheid biedt een implementatie voor een methode met de naam tussen om de hoeveelheid tijd tussen twee tijdelijke objecten te berekenen in termen van die specifieke eenheid.

Om bijvoorbeeld de seconden tussen twee te berekenen LocalDateTimes:

@Test openbare ongeldig gegevenTwoDateTimesInJava8_whenDifferentiatingInSeconds_thenWeGetTen () {LocalDateTime nu = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); lange diff = ChronoUnit.SECONDS.between (nu, tenSecondsLater); assertEquals (10, diff); }

ChronoUnit biedt een set van concrete tijdseenheden door de implementatie van de TemporalUnit koppel. Het wordt ten zeerste aanbevolen statische import de ChronoUnitopsomming waarden voor een betere leesbaarheid:

importeer statische java.time.temporal.ChronoUnit.SECONDS; // weggelaten lange diff = SECONDS.between (nu, tenSecondsLater);

We kunnen ook twee compatibele tijdelijke objecten doorgeven aan het tussen methode, zelfs de ZonedDateTime.

Wat is er geweldig aan ZonedDateTime is dat de berekening zal werken, zelfs als ze zijn ingesteld op verschillende tijdzones:

@Test openbare ongeldig gegevenTwoZonedDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime ldt = LocalDateTime.now (); ZonedDateTime now = ldt.atZone (ZoneId.of ("America / Montreal")); ZonedDateTime sixMinutesBehind = nu .withZoneSameInstant (ZoneId.of ("Azië / Singapore")) .minusMinutes (6); lange diff = ChronoUnit.MINUTES.between (sixMinutesBehind, nu); assertEquals (6, diff); } 

2.3. Gebruik makend van java.time.temporal.Temporal # tot ()

Ieder Tijdelijk object, zoals LocalDate of ZonedDateTime, biedt een tot methode om de hoeveelheid tijd tot een ander te berekenen Tijdelijk in termen van de gespecificeerde eenheid:

@Test openbare ongeldig gegevenTwoDateTimesInJava8_whenDifferentiatingInSecondsUsingUntil_thenWeGetTen () {LocalDateTime nu = LocalDateTime.now (); LocalDateTime tenSecondsLater = now.plusSeconds (10); lange diff = now.until (tenSecondsLater, ChronoUnit.SECONDS); assertEquals (10, diff); }

De Tijdelijk # tot en TemporalUnit # tussen zijn twee verschillende API's voor dezelfde functionaliteit.

2.4. Gebruik makend van java.time.Duration en java.time.Period

In Java 8 introduceerde de Time API twee nieuwe klassen: Looptijd en Periode.

Als we het verschil tussen twee datum-tijden willen berekenen in een tijdgebaseerde (uur, minuten of seconden) hoeveelheid tijd, kunnen we de Looptijd klasse:

@Test openbare ongeldig gegevenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix () {LocalDateTime nu = LocalDateTime.now (); LocalDateTime sixMinutesBehind = now.minusMinutes (6); Duration duration = Duration.between (nu, sixMinutesBehind); lange diff = Math.abs (duration.toMinutes ()); assertEquals (6, diff); }

Echter, we moeten op onze hoede zijn voor een valkuil als we proberen de Periode klasse om het verschil tussen twee datums weer te geven.

Een voorbeeld zal het snel uitleggen. Laten we berekenen hoeveel dagen tussen twee datums met behulp van de Periode klasse:

@Test openbare ongeldig gegevenTwoDatesInJava8_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); }

Als we de bovenstaande test uitvoeren, zal deze slagen. We denken misschien dat de Periode klasse is handig om ons probleem op te lossen. Tot nu toe zo goed.

Als deze manier werkt met een verschil van zes dagen, twijfelen we er niet aan dat het ook 60 dagen zal werken.

Laten we vervolgens het 6 in de test hierboven naar 60, en kijk wat er gebeurt:

@Test openbare ongeldig gegevenTwoDatesInJava8_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); }

Als we de test opnieuw uitvoeren, zien we:

java.lang.AssertionError: Verwacht: 60 Werkelijk: 29

Oeps! Waarom heeft het Periode klasse rapporteert het verschil als 29 dagen?

Dit komt doordat de Periode class staat voor een op datum gebaseerde hoeveelheid tijd in de notatie 'x jaar, y maanden en z dagen“. Als we het noemen getDays () methode, retourneert het alleen de “z dagen" een deel.

Daarom, de periode object in de bovenstaande test bevat de waarde: "0 jaar, 1 maand en 29 dagen“:

@Test openbare ongeldig gegevenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days () {LocalDate aDate = LocalDate.of (2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays (60); Period period = Period.between (aDate, sixtyDaysBehind); int jaar = Math.abs (period.getYears ()); int maanden = Math.abs (period.getMonths ()); int dagen = Math.abs (period.getDays ()); assertArrayEquals (new int [] {0, 1, 29}, new int [] {jaren, maanden, dagen}); }

Als we het verschil in dagen willen berekenen met behulp van de Time API van Java 8, is de ChronoUnit.DAYS.between () methode is de meest eenvoudige manier.

3. Externe bibliotheken

3.1. JodaTime

We kunnen ook een relatief eenvoudige implementatie doen met JodaTime:

 joda-tijd joda-tijd 2.9.9 

U kunt de nieuwste versie van Joda-time downloaden van Maven Central.

LocalDate geval:

@Test openbare ongeldig gegevenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDate nu = org.joda.time.LocalDate.now (); org.joda.time.LocalDate sixDaysBehind = now.minusDays (6); lange diff = Math.abs (Days.daysBetween (nu, sixDaysBehind) .getDays ()); assertEquals (6, diff); } 

Evenzo met LocalDateTime het is:

@Test openbare ongeldig gegevenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix () {org.joda.time.LocalDateTime nu = org.joda.time.LocalDateTime.now (); org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes (6); lange diff = Math.abs (Minutes.minutesBetween (nu, sixMinutesBehind) .getMinutes ()); assertEquals (6, diff); } 

3.2. Datum4J

Date4j biedt ook een ongecompliceerde en eenvoudige implementatie, zonder de opmerking dat we in dit geval expliciet een Tijdzone.

Laten we beginnen met de Maven-afhankelijkheid:

 com.darwinsys hirondelle-date4j 1.5.1 

Hier is een korte test om met de standaard te werken Datum Tijd:

@Test openbare ongeldig gegevenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix () {DateTime now = DateTime.now (TimeZone.getDefault ()); DateTime sixDaysBehind = now.minusDays (6); lange diff = Math.abs (now.numDaysFrom (sixDaysBehind)); assertEquals (6, diff); }

4. Conclusie

In deze tutorial hebben we een paar manieren geïllustreerd om het verschil tussen datums (met en zonder tijd) te berekenen, zowel in gewoon Java als met behulp van externe bibliotheken.

De volledige broncode van het artikel is beschikbaar op GitHub.