Eine Anleitung zu SimpleDateFormat

1. Einleitung

In diesem Tutorial werden wir eine ausführliche Tour durch die SimpleDateFormat- Klasse machen .

Wir werden uns einfache Instanziierungs- und Formatierungsstile sowie nützliche Methoden ansehen , die die Klasse für die Behandlung von Gebietsschemas und Zeitzonen bereitstellt .

2. Einfache Instanziierung

Schauen wir uns zunächst an, wie ein neues SimpleDateFormat- Objekt instanziiert wird.

Es gibt 4 mögliche Konstruktoren - aber im Einklang mit dem Namen lassen Sie uns die Dinge einfach halten. Alles, was wir brauchen, um loszulegen, ist eine String- Darstellung eines gewünschten Datumsmusters .

Beginnen wir mit einem durch Striche getrennten Datumsmuster wie folgt:

"dd-MM-yyyy"

Dadurch wird ein Datum korrekt formatiert, das mit dem aktuellen Tag des Monats, dem aktuellen Monat des Jahres und schließlich dem aktuellen Jahr beginnt. Wir können unseren neuen Formatierer mit einem einfachen Komponententest testen. Wir werden ein neues SimpleDateFormat- Objekt instanziieren und ein bekanntes Datum übergeben:

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); assertEquals("24-05-1977", formatter.format(new Date(233345223232L))); 

In dem obigen Code, die Formatierer wandelt Millisekunden als l ong in eine menschenlesbare Datum - der 24. Mai 1977.

2.1. Fabrikmethoden

Obwohl SimpleDateFormat eine praktische Klasse zum schnellen Erstellen eines Datumsformatierers ist, wird empfohlen, die Factory-Methoden für die DateFormat- Klassen getDateFormat () , getDateTimeFormat () , getTimeFormat () zu verwenden .

Das obige Beispiel sieht bei Verwendung dieser Factory-Methoden etwas anders aus:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT); assertEquals("5/24/77", formatter.format(new Date(233345223232L)));

Wie wir oben sehen können, wird die Anzahl der Formatierungsoptionen durch die Felder in der DateFormat- Klasse vorgegeben . Dies schränkt unsere verfügbaren Formatierungsoptionen weitgehend ein, weshalb wir uns in diesem Artikel an SimpleDateFormat halten .

2.2. Gewindesicherheit

Das JavaDoc für SimpleDateFormat gibt explizit an:

Datumsformate werden nicht synchronisiert. Es wird empfohlen, für jeden Thread separate Formatinstanzen zu erstellen. Wenn mehrere Threads gleichzeitig auf ein Format zugreifen, muss es extern synchronisiert werden.

Daher sind SimpleDateFormat- Instanzen nicht threadsicher , und wir sollten sie in gleichzeitigen Umgebungen sorgfältig verwenden.

Der beste Ansatz, um dieses Problem zu behebenist es, sie in Kombination mit einem ThreadLocal zu verwenden . Auf diese Weise erhält jeder Thread eine eigene SimpleDateFormat- Instanz, und die fehlende Freigabe macht das Programm threadsicher:

private final ThreadLocal formatter = ThreadLocal .withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));

Das Argument für die withInitial- Methode ist ein Anbieter von SimpleDateFormat- Instanzen. Jedes Mal, wenn ThreadLocal eine Instanz erstellen muss, wird dieser Lieferant verwendet.

Dann können wir den Formatierer über die ThreadLocal- Instanz verwenden:

formatter.get().format(date)

Die ThreadLocal.get () -Methode initialisiert zuerst das SimpleDateFormat für den aktuellen Thread und verwendet diese Instanz dann erneut.

Wir nennen diese Technik Thread-Beschränkung, da wir die Verwendung jeder Instanz auf einen bestimmten Thread beschränken.

Es gibt zwei weitere Ansätze, um dasselbe Problem anzugehen:

  • Verwenden synchronisierter Blöcke oder ReentrantLock s
  • Erstellen von Instanzen von SimpleDateFormat bei Bedarf

Beide Ansätze werden nicht empfohlen: Ersteres führt zu erheblichen Leistungseinbußen, wenn die Konkurrenz hoch ist, und letzteres erzeugt viele Objekte, wodurch die Speicherbereinigung unter Druck gesetzt wird.

Es ist erwähnenswert, dass seit Java 8 eine neue DateTimeFormatter- Klasse eingeführt wurde . Die neue DateTimeFormatter- Klasse ist unveränderlich und threadsicher. Wenn wir mit Java 8 oder höher arbeiten, wird die Verwendung der neuen DateTimeFormatter- Klasse empfohlen.

3. Daten analysieren

Mit SimpleDateFormat und DateFormat können wir nicht nur Datumsangaben formatieren, sondern auch den Vorgang umkehren. Mit der Analysemethode können wir die Zeichenfolgendarstellung eines Datums eingeben und das Datumsobjektäquivalent zurückgeben :

SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); Date myDate = new Date(233276400000L); Date parsedDate = formatter.parse("24-05-1977"); assertEquals(myDate.getTime(), parsedDate.getTime());

Hierbei ist zu beachten, dass das im Konstruktor bereitgestellte Muster dasselbe Format haben sollte wie das mit der Analysemethode analysierte Datum .

4. Datums- / Uhrzeitmuster

SimpleDateFormat bietet eine Vielzahl verschiedener Optionen für die Formatierung von Daten. Während die vollständige Liste in den JavaDocs verfügbar ist, wollen wir einige der am häufigsten verwendeten Optionen untersuchen:

Brief Datumskomponente Beispiel
M. Monat 12; Dez.
y Jahr 94
d Tag 23; Mo.
H. Stunde 03
m Minute 57

Die Ausgabe von der Datumskomponente zurück hängt auch stark von der Anzahl der verwendeten Zeichen im String . Nehmen wir zum Beispiel den Monat Juni. Wenn wir die Datumszeichenfolge definieren als:

"MM"

Dann erscheint unser Ergebnis als Zahlencode - 06. Wenn wir jedoch unserer Datumszeichenfolge ein weiteres M hinzufügen:

"MMM"

Dann erscheint unser resultierendes formatiertes Datum als das Wort Jun .

5. Anwenden von Gebietsschemas

Die SimpleDateFormat- Klasse unterstützt auch eine Vielzahl von Gebietsschemas, die beim Aufruf des Konstruktors festgelegt werden.

Lassen Sie uns dies in die Praxis umsetzen, indem wir ein Datum auf Französisch formatieren. Wir instanziieren ein SimpleDateFormat- Objekt, während wir dem Konstruktor Locale.FRANCE bereitstellen .

SimpleDateFormat franceDateFormatter = new SimpleDateFormat("EEEEE dd-MMMMMMM-yyyy", Locale.FRANCE); Date myWednesday = new Date(1539341312904L); assertTrue(franceDateFormatter.format(myWednesday).startsWith("vendredi"));

Durch die Angabe eines bestimmten Datums, eines Mittwochnachmittags, können wir bestätigen, dass unser franceDateFormatter das Datum korrekt formatiert hat. Der neue Termin beginnt korrekt mit Vendredi- Französisch für Mittwoch!

In der Gebietsschema-Version des Konstruktors ist ein kleines Problem zu beachten. Obwohl viele Gebietsschemas unterstützt werden, kann keine vollständige Abdeckung garantiert werden . Oracle empfiehlt die Verwendung der Factory-Methoden für die DateFormat- Klasse, um die Abdeckung des Gebietsschemas sicherzustellen.

6. Ändern der Zeitzonen

Da SimpleDateFormat die DateFormat- Klasse erweitert, können wir die Zeitzone auch mit der setTimeZone- Methode bearbeiten . Schauen wir uns das in Aktion an:

Date now = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE dd-MMM-yy HH:mm:ssZ"); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London")); logger.info(simpleDateFormat.format(now)); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York")); logger.info(simpleDateFormat.format(now));

In the above example, we supply the same Date to two different time zones on the same SimpleDateFormat object. We've also added the ‘Z' character to the end of the pattern String to indicate the time zone differences. The output from the format method is then logged for the user.

Hitting run, we can see the current times relative to the two time zones:

INFO: Friday 12-Oct-18 12:46:14+0100 INFO: Friday 12-Oct-18 07:46:14-0400

7. Summary

In this tutorial, we've taken a deep dive into the intricacies of SimpleDateFormat.

We've looked at how to instantiate SimpleDateFormat as well as how the pattern String impacts how the date is formatted.

Wir haben mit dem Ändern der Gebietsschemas des Ausgabe-Strings herumgespielt, bevor wir schließlich mit der Verwendung von Zeitzonen experimentiert haben .

Wie immer finden Sie den vollständigen Quellcode auf GitHub.