Einführung in die Joda-Zeit

Einführung in die Joda-Zeit

1. Einführung

Joda-Time ist die vor der Veröffentlichung von Java 8 am häufigsten verwendete Bibliothek zur Verarbeitung von Datum und Uhrzeit. Ziel war es, eine intuitive API für die Verarbeitung von Datum und Uhrzeit bereitzustellen und die in der Java-API für Datum und Uhrzeit auftretenden Entwurfsprobleme zu beheben.

The central concepts implemented in this library were introduced in the JDK core with the release of the Java 8 version. Die neue Datums- und Uhrzeit-API befindet sich im Paketjava.time (JSR-310). Eine Übersicht über diese Funktionen finden Sie inarticle.

Nach der Veröffentlichung von Java 8 betrachten die Autoren das Projekt als weitgehend abgeschlossen und empfehlen, wenn möglich die Java 8-API zu verwenden.

2. Warum Joda-Time verwenden?

Die Datums- / Uhrzeit-API vor Java 8 hatte mehrere Entwurfsprobleme.

Zu den Problemen gehört die Tatsache, dass die KlassenDate undSimpleDateFormatternicht threadsicher sind. Um dieses Problem zu beheben,Joda-Time uses immutable classes for handling date and time.

Die KlasseDatetellt kein tatsächliches Datum dar, sondern gibt einen Zeitpunkt mit Millisekundengenauigkeit an. Das Jahr inDate beginnt ab 1900, während die meisten Datumsoperationen normalerweise die Epochenzeit verwenden, die am 1. Januar 1970 beginnt.

Auch der Tag-, Monats- und Jahresversatz vonDate ist nicht intuitiv. Die Tage beginnen bei 0, während der Monat bei 1 beginnt. Um auf einen von ihnen zugreifen zu können, müssen wir die KlasseCalendarverwenden. Joda-Time offers a clean and fluent API for handling dates and time.

Joda-Time bietet auchsupport for eight calendar systems, während Java nur 2 bietet: Gregorianisch -java.util.GregorianCalendar und Japanisch -java.util.JapaneseImperialCalendar.

 3. Konfiguration

Um die Funktionalität der Joda-Time-Bibliothek einzuschließen, müssen wir die folgende Abhängigkeit vonMaven Central hinzufügen:


    joda-time
    joda-time
    2.10

 4. Bibliotheksübersicht

Joda-Time modelliert dieconcept of date and time unter Verwendung der Klassen im Paketorg.joda.time.

Unter diesen Klassen sind die am häufigsten verwendeten:

  • LocalDate - repräsentiert ein Datum ohne Zeit

  • LocalTime - repräsentiert die Zeit ohne Zeitzone

  • LocalDateTime - repräsentiert sowohl das Datum als auch die Uhrzeit ohne Zeitzone

  • Instant - repräsentiert einen genauen Zeitpunkt in Millisekunden ab der Java-Epoche von 1970-01-01T00: 00: 00Z

  • Duration - repräsentiert die Dauer in Millisekunden zwischen 2 Zeitpunkten

  • Period - ähnlich wieDuration, ermöglicht jedoch den Zugriff auf einzelne Komponenten des Datums- und Zeitobjekts wie Jahre, Monat, Tage usw.

  • Interval - repräsentiert das Zeitintervall zwischen 2 Zeitpunkten

Andere wichtige Merkmale sind diedate parsers and formatters. Diese finden Sie im Paketorg.joda.time.format.

Die spezifischen Klassen voncalendar system and time zonefinden Sie in den Paketen vonorg.joda.time.chrono and org.joda.time.tz.

Schauen wir uns einige Beispiele an, in denen wir die wichtigsten Funktionen von Joda-Time verwenden, um Datum und Uhrzeit zu verarbeiten.

5. Darstellen von Datum und Uhrzeit

5.1. Aktuelles Datum und Uhrzeit

The current date, without time information, kann unter Verwendung dernow()-Methode aus the LocalDate class erhalten werden:

LocalDate currentDate = LocalDate.now();

Wenn wir nur die aktuelle Uhrzeit ohne Datumsangabe benötigen, können wir die KlasseLocalTimeverwenden:

LocalTime currentTime = LocalTime.now();

Um einrepresentation of the current date and time without considering the time zone, we can use LocalDateTime zu erhalten:

LocalDateTime currentDateAndTime = LocalDateTime.now();

MitcurrentDateAndTime können wir es jetzt in die anderen Objekttypen konvertieren, die Datum und Uhrzeit modellieren.

Mit der MethodetoDateTime() können wir einDateTime-Objekt (das die Zeitzone berücksichtigt) erhalten. Wenn keine Zeit erforderlich ist, können wir sie mit der MethodetoLocalDate() inLocalDate konvertieren. Wenn wir nur die Zeit benötigen, können wirtoLocalTime() verwenden, um einLocalTime-Objekt zu erhalten:

DateTime dateTime = currentDateAndTime.toDateTime();
LocalDate localDate = currentDateAndTime.toLocalDate();
LocalTime localTime = currentDateAndTime.toLocalTime();

All the above methods have an overloaded method which accepts a DateTimeZone object, um das Datum oder die Uhrzeit in der angegebenen Zeitzone darzustellen:

LocalDate currentDate = LocalDate.now(DateTimeZone.forID("America/Chicago"));

Darüber hinaus bietet Joda-Time eine hervorragende Integration in die Java-API für Datum und Uhrzeit. Die Konstruktoren akzeptieren einjava.util.Date-Objekt und wir können auch dietoDate()-Methode verwenden, um einjava.util.Date-Objekt zurückzugeben:

LocalDateTime currentDateTimeFromJavaDate = new LocalDateTime(new Date());
Date currentJavaDate = currentDateTimeFromJavaDate.toDate();

5.2. Benutzerdefiniertes Datum und Uhrzeit

Zur Darstellung von Datum und Uhrzeit stellt Joda-Time verschiedene Konstruktoren zur Verfügung. Wir können die folgenden Objekte angeben:

  • einInstant

  • ein JavaDate Objekt

  • aString Darstellung von Datum und Uhrzeit im ISO-Format

  • Teile von Datum und Uhrzeit: Jahr, Monat, Tag, Stunde, Minute, Sekunde, Millisekunde

Date oneMinuteAgoDate = new Date(System.currentTimeMillis() - (60 * 1000));
Instant oneMinutesAgoInstant = new Instant(oneMinuteAgoDate);

DateTime customDateTimeFromInstant = new DateTime(oneMinutesAgoInstant);
DateTime customDateTimeFromJavaDate = new DateTime(oneMinuteAgoDate);
DateTime customDateTimeFromString = new DateTime("2018-05-05T10:11:12.123");
DateTime customDateTimeFromParts = new DateTime(2018, 5, 5, 10, 11, 12, 123);

Eine andere Möglichkeit, ein benutzerdefiniertes Datum und eine benutzerdefinierte Uhrzeit zu definieren, besteht darin, die Darstellung eines Datums und einer Uhrzeit inStringim ISO-Format zu analysieren:

DateTime parsedDateTime = DateTime.parse("2018-05-05T10:11:12.123");

Wir können auch benutzerdefinierte Darstellungen eines Datums und einer Uhrzeit analysieren, indem wir benutzerdefinierteDateTimeFormatter definieren:

DateTimeFormatter dateTimeFormatter
  = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss");
DateTime parsedDateTimeUsingFormatter
  = DateTime.parse("05/05/2018 10:11:12", dateTimeFormatter);

6. Mit Datum und Uhrzeit arbeiten

6.1. Verwenden vonInstant

EinInstant repräsentiert die Anzahl der Millisekunden von 1970-01-01T00: 00: 00Z bis zu einem bestimmten Zeitpunkt. Zum Beispiel kann der aktuelle Zeitpunkt mit dem Standardkonstruktor oder der Methodenow() ermittelt werden:

Instant instant = new Instant();
Instant.now();

Um einInstant für einen benutzerdefinierten Zeitpunkt zu erstellen, können Sie entweder einen der Konstruktoren oder die MethodenofEpochMilli() undofEpochSecond() verwenden:

Instant instantFromEpochMilli
  = Instant.ofEpochMilli(milliesFromEpochTime);
Instant instantFromEpocSeconds
  = Instant.ofEpochSecond(secondsFromEpochTime);

Die Konstruktoren akzeptieren einString, das ein Datum und eine Uhrzeit im ISO-Format darstellt, ein JavaDate oder einlong-Wert, der die Anzahl der Millisekunden von 1970-01-01T00: 00: 00Z: darstellt.

Instant instantFromString
  = new Instant("2018-05-05T10:11:12");
Instant instantFromDate
  = new Instant(oneMinuteAgoDate);
Instant instantFromTimestamp
  = new Instant(System.currentTimeMillis() - (60 * 1000));

Wenn Datum und Uhrzeit alsString dargestellt werden, haben wir die Möglichkeit, dieString in unserem gewünschten Format zu analysieren:

Instant parsedInstant
  = Instant.parse("05/05/2018 10:11:12", dateTimeFormatter);

Nachdem wir nun wissen, wasInstant darstellt und wie wir eines erstellen können, wollen wir sehen, wie es verwendet werden kann.

Zum Vergleich mitInstant Objekten können wircompareTo() verwenden, da es dieComparable Schnittstelle implementiert, aber wir können auch die Joda-Time API-Methoden verwenden, die in derReadableInstant Schnittstelle bereitgestellt werden, dieInstant implementiert auch:

assertTrue(instantNow.compareTo(oneMinuteAgoInstant) > 0);
assertTrue(instantNow.isAfter(oneMinuteAgoInstant));
assertTrue(oneMinuteAgoInstant.isBefore(instantNow));
assertTrue(oneMinuteAgoInstant.isBeforeNow());
assertFalse(oneMinuteAgoInstant.isEqual(instantNow));

Eine weitere hilfreiche Funktion istInstant can be converted to a DateTime object or event a Java Date:

DateTime dateTimeFromInstant = instant.toDateTime();
Date javaDateFromInstant = instant.toDate();

Wenn wir auf Teile eines Datums und einer Uhrzeit zugreifen müssen, wie z. B. das Jahr, die Stunde usw., können wir die Methodeget()verwenden undDateTimeFieldangeben:

int year = instant.get(DateTimeFieldType.year());
int month = instant.get(DateTimeFieldType.monthOfYear());
int day = instant.get(DateTimeFieldType.dayOfMonth());
int hour = instant.get(DateTimeFieldType.hourOfDay());

Nachdem wir uns nun mit der KlasseInstantbefasst haben, sehen wir uns einige Beispiele an, wie wirDuration,Period undInterval verwenden können.

6.2. Verwenden SieDuration,Period undInterval

EinDuration repräsentiert die Zeit in Millisekunden zwischen zwei Zeitpunkten oder in diesem Fall zweiInstants. We’ll use this when we need to add or subtract a specific amount of time to or from another Instant without considering chronology and time zones:

long currentTimestamp = System.currentTimeMillis();
long oneHourAgo = currentTimestamp - 24*60*1000;
Duration duration = new Duration(oneHourAgo, currentTimestamp);
Instant.now().plus(duration);

Außerdem können wir bestimmen, wie viele Tage, Stunden, Minuten, Sekunden oder Millisekunden die Dauer darstellt:

long durationInDays = duration.getStandardDays();
long durationInHours = duration.getStandardHours();
long durationInMinutes = duration.getStandardMinutes();
long durationInSeconds = duration.getStandardSeconds();
long durationInMilli = duration.getMillis();

Der Hauptunterschied zwischenPeriod undDuration besteht darin, dassPeriod is defined in terms of its date and time components (years, months, hours, etc.) and doesn’t represent an exact number of milliseconds. Bei Verwendung vonPeriod Datums- und Zeitberechnungenwill consider the time zone and daylight saving.

Wenn Sie beispielsweise dem 1. Februar einenPeriod von 1 Monat hinzufügen, wird das Datum am 1. März dargestellt. Durch die Verwendung vonPeriod berücksichtigt die Bibliothek Schaltjahre.

Wenn wirDuration verwenden, ist das Ergebnis nicht korrekt, daDuration eine feste Zeitspanne darstellt, die Chronologie oder Zeitzonen nicht berücksichtigt:

Period period = new Period().withMonths(1);
LocalDateTime datePlusPeriod = localDateTime.plus(period);

EinInterval repräsentiert, wie der Name schon sagt, das Datum und das Zeitintervall zwischen zwei festen Zeitpunkten, die durch zweiInstant-Objekte dargestellt werden:

Interval interval = new Interval(oneMinuteAgoInstant, instantNow);

Die Klasse ist nützlich, wenn wir prüfen müssen, ob sich zwei Intervalle überlappen, oder die Lücke zwischen ihnen berechnen müssen. Die Methodeoverlap() gibt die überlappendenInterval odernull zurück, wenn sie sich nicht überlappen:

Instant startInterval1 = new Instant("2018-05-05T09:00:00.000");
Instant endInterval1 = new Instant("2018-05-05T11:00:00.000");
Interval interval1 = new Interval(startInterval1, endInterval1);

Instant startInterval2 = new Instant("2018-05-05T10:00:00.000");
Instant endInterval2 = new Instant("2018-05-05T11:00:00.000");
Interval interval2 = new Interval(startInterval2, endInterval2);

Interval overlappingInterval = interval1.overlap(interval2);

Die Differenz zwischen Intervallen kann mit dergap()-Methode berechnet werden. Wenn wir wissen möchten, ob das Ende eines Intervalls dem Beginn eines anderen Intervalls entspricht, können wir dieabuts()-Methode verwenden:

assertTrue(interval1.abuts(new Interval(
  new Instant("2018-05-05T11:00:00.000"),
  new Instant("2018-05-05T13:00:00.000"))));

6.3. Datums- und Zeitvorgänge

Einige der häufigsten Operationen sind das Hinzufügen, Subtrahieren und Konvertieren von Datum und Uhrzeit. Die Bibliothek bietet spezifische Methoden für jede der KlassenLocalDate,LocalTime,LocalDateTime undDateTime. Es ist wichtig zu beachten, dass diese Klassen unveränderlich sind, damit bei jedem Methodenaufruf ein neues Objekt seines Typs erstellt wird.

Nehmen wirLocalDateTime für den aktuellen Moment und versuchen, seinen Wert zu ändern:

LocalDateTime currentLocalDateTime = LocalDateTime.now();

UmcurrentLocalDateTime einen zusätzlichen Tag hinzuzufügen, verwenden wir die MethodeplusDays():

LocalDateTime nextDayDateTime = currentLocalDateTime.plusDays(1);

Wir können auch die Methodeplus() verwenden, umPeriod oderDuration zu unserencurrentLocalDateTime: hinzuzufügen

Period oneMonth = new Period().withMonths(1);
LocalDateTime nextMonthDateTime = currentLocalDateTime.plus(oneMonth);

Die Methoden sind für die anderen Datums- und Zeitkomponenten ähnlich, z. B.plusYears() zum Hinzufügen zusätzlicher Jahre, plus Sekunden () zum Hinzufügen weiterer Sekunden usw.

Um einen Tag von unserencurrentLocalDateTime zu subtrahieren, können wir dieminusDays()-Methode verwenden:

LocalDateTime previousDayLocalDateTime
  = currentLocalDateTime.minusDays(1);

Außerdem können wir bei Berechnungen mit Datum und Uhrzeit auch einzelne Teile des Datums oder der Uhrzeit einstellen. Zum Beispiel kann die Einstellung der Stunde auf 10 mit der MethodewithHourOfDay() erreicht werden. Andere Methoden, die mit dem Präfix“with” beginnen, können verwendet werden, um Komponenten dieses Datums oder dieser Uhrzeit festzulegen:

LocalDateTime currentDateAtHour10 = currentLocalDateTime
  .withHourOfDay(0)
  .withMinuteOfHour(0)
  .withSecondOfMinute(0)
  .withMillisOfSecond(0);

Ein weiterer wichtiger Aspekt ist, dass wir von einem Datums- und Zeitklassentyp in einen anderen konvertieren können. Dazu können wir bestimmte Methoden verwenden, die von der Bibliothek bereitgestellt werden:

  • toDateTime() - konvertiertLocalDateTime in einDateTime-Objekt

  • toLocalDate() - konvertiertLocalDateTime in einLocalDate-Objekt

  • toLocalTime () - konvertiert LocalDateTime in ein LocalTime-Objekt

  • toDate() - konvertiertLocalDateTime in ein JavaDate-Objekt

7. Mit Zeitzonen arbeiten

Joda-Time erleichtert es uns, mit verschiedenen Zeitzonen zu arbeiten und zwischen diesen zu wechseln. Wir haben die abstrakte KlasseDateTimeZone, mit der alle Aspekte einer Zeitzone dargestellt werden.

The default time zone used by Joda-Time is selected from the user.timezone Java system property. Mit der Bibliotheks-API können wir für jede Klasse oder Berechnung individuell festlegen, welche Zeitzone verwendet werden soll. Beispielsweise können wir ein LocalDateTime-Objekt erstellen

Wenn wir wissen, dass wir eine bestimmte Zeitzone für die gesamte Anwendung verwenden, können wir die Standardzeitzone festlegen:

DateTimeZone.setDefault(DateTimeZone.UTC);

Ab sofort werden alle Datums- und Zeitvorgänge, sofern nicht anders angegeben, in der UTC-Zeitzone dargestellt.

Um alle verfügbaren Zeitzonen anzuzeigen, können wir die MethodegetAvailableIDs(): verwenden

DateTimeZone.getAvailableIDs()

Wenn wir das Datum oder die Uhrzeit in einer bestimmten Zeitzone darstellen müssen, können wir eine der KlassenLocalTime,LocalDate,LocalDateTime,DateTime verwenden und im Konstruktor die angeben DateTimeZone Objekt:

DateTime dateTimeInChicago
  = new DateTime(DateTimeZone.forID("America/Chicago"));
DateTime dateTimeInBucharest
  = new DateTime(DateTimeZone.forID("Europe/Bucharest"));
LocalDateTime localDateTimeInChicago
  = new LocalDateTime(DateTimeZone.forID("America/Chicago"));

Außerdem können wir beim Konvertieren zwischen diesen Klassen die gewünschte Zeitzone angeben. Die MethodetoDateTime() akzeptiert einDateTimeZone-Objekt undtoDate() akzeptiert das java.util.TimeZone-Objekt:

DateTime convertedDateTime
  = localDateTimeInChicago.toDateTime(DateTimeZone.forID("Europe/Bucharest"));
Date convertedDate
  = localDateTimeInChicago.toDate(TimeZone.getTimeZone("Europe/Bucharest"));

8. Fazit

Joda-Time ist eine fantastische Bibliothek, die mit dem Hauptziel begann, die Probleme im JDK bezüglich Datum und Uhrzeit zu beheben. Es wurde bald zurde facto-Bibliothek für Datums- und Zeitverarbeitung, und kürzlich wurden die wichtigsten Konzepte daraus in Java 8 eingeführt.

Es ist wichtig zu beachten, dass der Autor“to be a largely finished project” berücksichtigt und empfiehlt, den vorhandenen Code zu migrieren, um die Java 8-Implementierung zu verwenden.

Der Quellcode für den Artikel istover on GitHub verfügbar.