DateUtils in Apache Commons

Wer zum ersten Mal als Entwickler das Thema Datum/Kalender berührt, denkt sich meist, dass es sich hier gar nicht um ein komplexes Thema handeln kann. Schließlich hat man damit täglich zu tun und empfindet es als einfaches Konzept. Tatsächlich gibt es bei diesem Themenbereich aber eine besonders große Kluft zwischen dem, wie man als Einzelperson im täglichen Leben damit umgeht, und dem, was eine Software berücksichtigen muss.

Diese große Kluft ergibt sich vor allem durch die international verwendeten Zeitzonen und eventuelle Sommerzeiten. Die Komplexität entsteht dadurch, dass es international bei Sommerzeiten keine einheitlichen Richtlinie gibt, d.h. weder der Tag noch die Uhrzeit, zu der in einem bestimmten Land umgestellt wird, ist einheitlich. Auch die Datumsarithmetik, also das Rechnen mit Daten, ist nicht so banal, wie man annehmen möchte (hier eine kleine Zusammenstellung).

International verwendete Software muss diese leider sehr heterogenen Regeln aber korrekt abbilden, was zu hochkomplexen Bibliotheken führt. Wenn du schon einige Zeit mit Java programmierst, hast du sicher schon festgestellt, dass die dort verwendeten APIs für Entwickler oftmals nicht intuitiv verwendbar sind. Tägliche Standardaufgaben wie das Erstellen eines Date-Objekts, das beispielsweise einen Geburtstag repräsentieren soll, und zum Abspeichern in der Datenbank unter Verwendung von Hibernate gedacht ist, nehmen dadurch mehr Zeit in Anspruch, als man als Entwickler möchte und haben auch ein großes Bug-Potential.

Mit Java 8 kommt zu dieser Thematik eine neue API heraus, die einerseits die bisherigen APIs konsolidieren und ablösen möchte, und andererseits auch bisher fehlende Konzepte abbilden will (wie z.B. ein Datum, das keine Uhrzeit beinhaltet, was für Geburtsdaten u.ä. sehr nützlich ist).

An schon bestehenden Hilfsmitteln, die einem als Entwickler zu diesem Thema bis dahin zur Verfügung stehen (und vermutlich auch danach noch ihren Einsatzzweck in abgewandelter Form haben werden), möchte ich eine kleine Einführung zu den DateUtils von Apache Commons geben.

Ein paar der wichtigsten davon angebotenen Funktionalitäten, thematisch zusammengefasst (die Codebeispiele sind nur auszugsweise und bilden nicht alle Methoden ab):

  • Hinzufügen oder Abziehen von Zeitabschnitten zu Daten:

Usecase: Ein Benutzer wird angelegt und ist ab Anlagedatum 8 Wochen lang gültig. Das “gültig bis”-Datum kann hiermit leicht errechnet werden.

DateUtils.addWeeks(new Date(), 8);

Weitere Methoden dieser Art:

DateUtils.addHours(date, 1);
DateUtils.addDays(date, 1);
DateUtils.addYears(date, 1);
  • Vergleiche zwischen Daten, d.h. ob ein Datum inhaltlich einem anderen entspricht (mit Berücksichtigung der im täglichen Leben am häufigsten vorkommenden Fälle)

Usecase: Beim Anlegen eines Benutzers wird das Anlagedatum gespeichert. Zur Analyse der Beliebtheit soll eine Aufstellung gemacht werden, wieviele User jeweils am selben Tag erstellt wurden, die Uhrzeit soll nicht berücksichtigt werden.

Date now = new Date();
int created = 0;
for (Date creationDate: getAllCreationDates()) {
    if (DateUtils.isSameDay(now, creationDate)) {
        created++;
    }
}

Weitere Methoden dieser Art:

DateUtils.isSameInstant(date1, date2);
DateUtils.truncatedEquals(date1, date2, Calendar.YEAR);
  • Zeitabschnitte in einem Datum setzen

Usecase: Im Programmverlauf muss ein Datumsobjekt erstellt werden, das ein fixes Datum repräsentiert.

Date date = DateUtils.setYears(new Date(), 1980);
date = DateUtils.setMonths(date, 11); //Zählung beginnt mit 0
date = DateUtils.setDays(date, 1); // Zählung beginnt mit 1
  • Parser

Usecase: Eingabedaten von Endusern sind nur als Strings verfügbar, sollen aber in der Datenbank korrekt als Date-Objekte gespeichert werden. Der Kunde wünscht sich, dass unterschiedlichste Datumseingaben akzeptiert werden sollen, um eine möglichst hohe Usability zu bieten.

String[] datesAsString = { "01.01.2000", "10-13-99"};
for (String dateAsString: datesAsString) {
     DateUtils.parseDate(dateAsString, "dd.mm.yyyy", "mm-dd-yy");
}

Die DateUtils Klasse bietet zusätzlich noch Methoden zum Zurückliefern von Teilen (getFragment…()), Runden und Abschneiden von Daten an (round() / ceiling() / truncate(); jeweils bezogen auf Zeitabschnitte wie Stunde, Tag, Jahr) und kann sehr einfach ein Datum zu einem java.util-Calendar Objekt konvertieren. Sie behandelt darüber hinaus Eingabedaten so, als ob sie immutable wären: sie werden nicht verändert, sondern neue Daten erstellt und zurückgegeben, was Fehler vermeiden hilft.

Insgesamt werden also viele der Aufgaben, die mit der java.util API mühsam zu implementieren sind, in der Usability für den Entwickler deutlich verbessert und erleichtern das tägliche Arbeiten ungemein.

Welche Aufgaben, die mit Daten zu tun haben, musstest du schon lösen, die durch Verwendung von DateUtils einfacher und sauberer gewesen wären?

Lisi Blümelhuber

Software Developer