Migration auf die neue Java 8 Date Time API

Migration auf die neue Java 8 Date Time API

1. Überblick

In diesem Tutorial erfahren Sie, wie Sie Ihren Code umgestalten, um die in Java 8 eingeführte neue 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 undjava.util.Timezone.

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

Java 8 introduced a completely new Date Time API (java.util.time.*), das lose auf der beliebten Java-Bibliothek namens JodaTime basiert. Diese neue API vereinfachte die Verarbeitung von Datum und Uhrzeit erheblich und behebte viele Mängel der alten Datumsbibliothek.

1.1. API-Klarheit

Ein erster Vorteil der neuen API istclarity - 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, in Wochentagen auf Eins).

1.2. API-Flexibilität

Ein weiterer Vorteil ist die Flexibilität -working with multiple representations of time. 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 seit der Unix-Epoche gespeichert.

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

  • Instant - repräsentiert einen Zeitpunkt (Zeitstempel)

  • LocalDate - steht für ein Datum (Jahr, Monat, Tag)

  • LocalDateTime - wieLocalDate, enthält jedoch Zeit mit Nanosekundengenauigkeit

  • OffsetDateTime - wieLocalDateTime, jedoch mit Zeitzonenversatz

  • LocalTime - Zeit mit Nanosekundengenauigkeit und ohne Datumsangabe

  • ZonedDateTime - wieOffsetDateTime, enthält jedoch eine Zeitzonen-ID

  • OffsetLocalTime - wieLocalTime, jedoch mit Zeitzonenversatz

  • MonthDay - Monat und Tag, ohne Jahr oder Zeit

  • YearMonth - Monat und Jahr, ohne Tag oder Uhrzeit

  • Duration - Zeitdauer in Sekunden, Minuten und Stunden. Hat Nanosekundengenauigkeit

  • Period - Zeitdauer in Tagen, Monaten und Jahren

1.3. Unveränderlichkeit und Gewindesicherheit

Ein weiterer Vorteil ist, dass alle Zeitdarstellungen in der Java 8 Date Time APIimmutable and thus thread-safe. sind

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

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

1.4. Methodenverkettung

Alle Mutationsmethoden können miteinander verkettet werden, so dass 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 sowohl mit der alten als auch mit 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

Beim Abschneiden werden alle Zeitfelder zurückgesetzt, die kleiner als das angegebene Feld sind. Im folgenden Beispiel werden die Minuten und alles darunter 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 mit 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 Date Time API untersucht, die in Java 8 verfügbar ist. Wir haben uns die Vorteile gegenüber der veralteten API angesehen und anhand mehrerer Beispiele auf Unterschiede hingewiesen.

Beachten Sie, dass wir die Funktionen der neuen Date Time API kaum verändert haben. Lesen Sie unbedingt die offizielle Dokumentation durch, um alle von der neuen API angebotenen Tools zu entdecken.

Codebeispiele finden Sie inGitHub project.