Unterschied zwischen zwei Daten in Java

1. Übersicht

In diesem kurzen Artikel werden wir verschiedene Möglichkeiten untersuchen, um die Differenz zwischen zwei Daten in Java zu berechnen.

2. Core Java

2.1. Verwenden von java.util.Date, um den Unterschied in Tagen zu ermitteln

Beginnen wir mit der Verwendung der Java-Kern-APIs, um die Berechnung durchzuführen und die Anzahl der Tage zwischen den beiden Daten zu bestimmen:

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

2.2. Verwenden von java.time.temporal.ChronoUnit, um den Unterschied zu finden

Die Zeit-API in Java 8 repräsentiert eine Einheit aus Datum und Uhrzeit, z. B. Sekunden oder Tage, über die TemporalUnit- Schnittstelle. Jede Einheit bietet eine Implementierung für eine Methode, die zwischen benannt ist , um die Zeitdauer zwischen zwei zeitlichen Objekten in Bezug auf diese bestimmte Einheit zu berechnen .

Um beispielsweise die Sekunden zwischen zwei LocalDateTime s zu berechnen :

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

ChronoUnit bietet eine Reihe konkreter Zeiteinheiten durch Implementierung der TemporalUnit- Schnittstelle. Es wird dringend empfohlen, die ChronoUnit- Aufzählungswerte statisch zu importieren , um eine bessere Lesbarkeit zu erzielen:

import static java.time.temporal.ChronoUnit.SECONDS; // omitted long diff = SECONDS.between(now, tenSecondsLater);

Außerdem können wir zwei beliebige kompatible temporale Objekte an die Between- Methode übergeben, sogar an die ZonedDateTime .

Das Tolle an ZonedDateTime ist, dass die Berechnung auch dann funktioniert, wenn sie auf unterschiedliche Zeitzonen eingestellt sind:

@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.between(sixMinutesBehind, now); assertEquals(6, diff); } 

2.3. Verwenden von java.time.temporal.Temporal # till ()

Jedes Temporal Objekt, wie LOCALDATE oder ZonedDateTime, stellt einen bis Methode , um die Menge an Zeit , bis ein anderen zu berechnen Temporal hinsichtlich der spezifizierten Einheit:

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

Die Temporal # bis und TemporalUnit # zwischen zwei verschiedene APIs für die gleiche Funktionalität.

2.4. Verwenden von java.time.Duration und java.time.Period

In Java 8 hat die Zeit-API zwei neue Klassen eingeführt: Dauer und Periode .

Wenn wir die Differenz zwischen zwei Datums- und Uhrzeitangaben in einer zeitbasierten Zeit (Stunde, Minuten oder Sekunden) berechnen möchten, können wir die Klasse Dauer verwenden :

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

Allerdings sollten wir vorsichtig bei einem pitfall, wenn wir die versuchen , mit Periode Klasse den Unterschied zwischen zwei Daten zu repräsentieren .

Ein Beispiel wird es schnell erklären. Berechnen wir anhand der Periodenklasse, wie viele Tage zwischen zwei Daten liegen :

@Test public void givenTwoDatesInJava8_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); }

Wenn wir den obigen Test ausführen, besteht er. Wir denken vielleicht, dass die Periodenklasse praktisch ist, um unser Problem zu lösen. So weit, ist es gut.

Wenn dieser Weg mit einer Differenz von sechs Tagen funktioniert, werden wir nicht bezweifeln, dass er auch 60 Tage lang funktioniert.

Als nächstes ändern wir die 6 im obigen Test auf 60 und sehen, was passiert:

@Test public void givenTwoDatesInJava8_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); }

Wenn wir den Test erneut ausführen, werden wir sehen:

java.lang.AssertionError: Expected :60 Actual :29

Hoppla! Warum hat die Periodenklasse den Unterschied als 29 Tage angegeben?

Dies liegt daran, dass die Periodenklasse eine datumsbasierte Zeitdauer im Format „ x Jahre, y Monate und z Tage “ darstellt. Wenn wir die Methode getDays () aufrufen , wird nur der Teil " z Tage " zurückgegeben.

Daher enthält das Periodenobjekt im obigen Test den Wert: „ 0 Jahre, 1 Monat und 29 Tage “:

@Test public void givenTwoDatesInJava8_whenUsingPeriod_thenWeGet0Year1Month29Days() { LocalDate aDate = LocalDate.of(2020, 9, 11); LocalDate sixtyDaysBehind = aDate.minusDays(60); Period period = Period.between(aDate, sixtyDaysBehind); int years = Math.abs(period.getYears()); int months = Math.abs(period.getMonths()); int days = Math.abs(period.getDays()); assertArrayEquals(new int[] { 0, 1, 29 }, new int[] { years, months, days }); }

Wenn wir die Differenz in Tagen mithilfe der Zeit-API von Java 8 berechnen möchten, ist die ChronoUnit.DAYS.between () -Methode der einfachste Weg.

3. Externe Bibliotheken

3.1. JodaTime

Mit JodaTime können wir auch eine relativ einfache Implementierung durchführen :

 joda-time joda-time 2.9.9 

Sie können die neueste Version von Joda-time von Maven Central erhalten.

LocalDate- Fall:

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

In ähnlicher Weise ist es mit LocalDateTime :

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

3.2. Date4J

Date4j bietet auch eine unkomplizierte und einfache Implementierung, ohne den Hinweis, dass wir in diesem Fall explizit eine Zeitzone bereitstellen müssen .

Beginnen wir mit der Maven-Abhängigkeit:

 com.darwinsys hirondelle-date4j 1.5.1 

Hier ist ein kurzer Test mit der Standard- DateTime :

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

4. Fazit

In diesem Tutorial haben wir einige Möglichkeiten zur Berechnung des Unterschieds zwischen Datumsangaben (mit und ohne Zeit) dargestellt, sowohl in einfachem Java als auch unter Verwendung externer Bibliotheken.

Der vollständige Quellcode des Artikels ist auf GitHub verfügbar.