Migration auf die neue Java 8 Date Time API

1. Übersicht

In diesem Tutorial erfahren Sie, wie Sie Ihren Code umgestalten, um die neue in Java 8 eingeführte Date Time API zu nutzen.

2. Neue API auf einen Blick

Früher war es schwierig, mit Daten in Java zu arbeiten. Die von JDK bereitgestellte alte Datumsbibliothek enthielt nur drei Klassen: java.util.Date, java.util.Calendar und java.util.Timezone .

Diese waren nur für die grundlegendsten Aufgaben geeignet. Für alles, was auch nur annähernd komplex ist, mussten die Entwickler entweder Bibliotheken von Drittanbietern verwenden oder Tonnen von benutzerdefiniertem Code schreiben.

Java 8 führte eine völlig neue Datums- und Uhrzeit-API ( java.util.time. * ) Ein, die lose auf der beliebten Java-Bibliothek namens JodaTime basiert. Diese neue API hat die Verarbeitung von Datum und Uhrzeit erheblich vereinfacht und viele Mängel der alten Datumsbibliothek behoben.

1.1. API-Klarheit

Ein erster Vorteil der neuen API ist die Klarheit - die API ist sehr klar, präzise und leicht zu verstehen. Es gibt nicht viele Inkonsistenzen in der alten Bibliothek, wie z. B. die Feldnummerierung (in Kalendermonaten basieren sie auf Null, Wochentage auf Eins).

1.2. API-Flexibilität

Ein weiterer Vorteil ist die Flexibilität - Arbeiten mit mehreren Zeitdarstellungen . Die alte Datumsbibliothek enthielt nur eine einzige Zeitrepräsentationsklasse - java.util.Date , die trotz ihres Namens tatsächlich ein Zeitstempel ist. Es wird nur die Anzahl der Millisekunden gespeichert, die seit der Unix-Epoche vergangen sind.

Die neue API verfügt über viele verschiedene Zeitdarstellungen, die jeweils für verschiedene Anwendungsfälle geeignet sind:

  • Sofort - repräsentiert einen Zeitpunkt (Zeitstempel)
  • LocalDate - repräsentiert ein Datum (Jahr, Monat, Tag)
  • LocalDateTime - wie LocalDate , enthält jedoch Zeit mit Nanosekundengenauigkeit
  • OffsetDateTime - wie LocalDateTime , jedoch mit Zeitzonenversatz
  • LocalTime - Zeit mit Nanosekundengenauigkeit und ohne Datumsangabe
  • ZonedDateTime - wie OffsetDateTime , enthält jedoch eine Zeitzonen-ID
  • OffsetLocalTime - wie LocalTime , jedoch mit Zeitzonenversatz
  • MonthDay - Monat und Tag, ohne Jahr oder Zeit
  • YearMonth - Monat und Jahr, ohne Tag und Uhrzeit
  • Dauer - Zeitdauer in Sekunden, Minuten und Stunden. Hat Nanosekundengenauigkeit
  • Zeitraum - Zeitspanne in Tagen, Monaten und Jahren

1.3. Unveränderlichkeit und Gewindesicherheit

Ein weiterer Vorteil ist, dass alle Zeitdarstellungen in der Java 8 Date Time API unveränderlich und somit threadsicher sind.

Alle Mutationsmethoden geben eine neue Kopie zurück, anstatt den Status des ursprünglichen Objekts zu ändern.

Alte Klassen wie java.util.Date waren nicht threadsicher und konnten sehr subtile Parallelitätsfehler verursachen.

1.4. Methodenverkettung

Alle Mutationsmethoden können miteinander verkettet werden, sodass komplexe Transformationen in einer einzigen Codezeile implementiert werden können.

ZonedDateTime nextFriday = LocalDateTime.now() .plusHours(1) .with(TemporalAdjusters.next(DayOfWeek.FRIDAY)) .atZone(ZoneId.of("PST")); 

2. Beispiele

Die folgenden Beispiele zeigen, wie allgemeine Aufgaben mit der alten und der neuen API ausgeführt werden.

Aktuelle Zeit abrufen

// Old Date now = new Date(); // New ZonedDateTime now = ZonedDateTime.now(); 

Repräsentation einer bestimmten Zeit

// Old Date birthDay = new GregorianCalendar(1990, Calendar.DECEMBER, 15).getTime(); // New LocalDate birthDay = LocalDate.of(1990, Month.DECEMBER, 15); 

Bestimmte Felder extrahieren

// Old int month = new GregorianCalendar().get(Calendar.MONTH); // New Month month = LocalDateTime.now().getMonth(); 

Zeit addieren und subtrahieren

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.HOUR_OF_DAY, -5); Date fiveHoursBefore = calendar.getTime(); // New LocalDateTime fiveHoursBefore = LocalDateTime.now().minusHours(5); 

Bestimmte Felder ändern

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.set(Calendar.MONTH, Calendar.JUNE); Date inJune = calendar.getTime(); // New LocalDateTime inJune = LocalDateTime.now().withMonth(Month.JUNE.getValue()); 

Abschneiden

Durch das Abschneiden werden alle Zeitfelder zurückgesetzt, die kleiner als das angegebene Feld sind. Im folgenden Beispiel werden Minuten und alles unten auf Null gesetzt

// Old Calendar now = Calendar.getInstance(); now.set(Calendar.MINUTE, 0); now.set(Calendar.SECOND, 0); now.set(Calendar.MILLISECOND, 0); Date truncated = now.getTime(); // New LocalTime truncated = LocalTime.now().truncatedTo(ChronoUnit.HOURS); 

Zeitzonenumrechnung

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeZone(TimeZone.getTimeZone("CET")); Date centralEastern = calendar.getTime(); // New ZonedDateTime centralEastern = LocalDateTime.now().atZone(ZoneId.of("CET")); 

Zeitspanne zwischen zwei Zeitpunkten ermitteln

// Old GregorianCalendar calendar = new GregorianCalendar(); Date now = new Date(); calendar.add(Calendar.HOUR, 1); Date hourLater = calendar.getTime(); long elapsed = hourLater.getTime() - now.getTime(); // New LocalDateTime now = LocalDateTime.now(); LocalDateTime hourLater = LocalDateTime.now().plusHours(1); Duration span = Duration.between(now, hourLater); 

Zeitformatierung und Analyse

DateTimeFormatter ist ein Ersatz für das alte SimpleDateFormat, das threadsicher ist und zusätzliche Funktionen bietet.

// Old SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date now = new Date(); String formattedDate = dateFormat.format(now); Date parsedDate = dateFormat.parse(formattedDate); // New LocalDate now = LocalDate.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedDate = now.format(formatter); LocalDate parsedDate = LocalDate.parse(formattedDate, formatter); 

Anzahl der Tage in einem Monat

// Old Calendar calendar = new GregorianCalendar(1990, Calendar.FEBRUARY, 20); int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); // New int daysInMonth = YearMonth.of(1990, 2).lengthOfMonth();

3. Interaktion mit Legacy-Code

In vielen Fällen muss ein Benutzer möglicherweise die Interoperabilität mit Bibliotheken von Drittanbietern sicherstellen, die auf der alten Datumsbibliothek basieren.

In Java 8 wurden alte Datumsbibliotheksklassen um Methoden erweitert, die sie von der neuen Datums-API in entsprechende Objekte konvertieren.

Neue Klassen bieten ähnliche Funktionen.

Instant instantFromCalendar = GregorianCalendar.getInstance().toInstant(); ZonedDateTime zonedDateTimeFromCalendar = new GregorianCalendar().toZonedDateTime(); Date dateFromInstant = Date.from(Instant.now()); GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from(ZonedDateTime.now()); Instant instantFromDate = new Date().toInstant(); ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone("PST").toZoneId(); 

4. Fazit

In diesem Artikel haben wir die neue Datums- / Uhrzeit-API untersucht, die in Java 8 verfügbar ist. Wir haben ihre Vorteile im Vergleich zur veralteten API untersucht und anhand mehrerer Beispiele auf Unterschiede hingewiesen.

Beachten Sie, dass wir die Funktionen der neuen Datums- und Uhrzeit-API kaum zerkratzt haben. Lesen Sie unbedingt die offizielle Dokumentation durch, um alle Tools der neuen API zu entdecken.

Codebeispiele finden Sie im GitHub-Projekt.