DateFormatter ist eine Foundation-Klasse, die für die bidirektionale Konvertierung zwischen Date-Objekten und deren Zeichenfolgendarstellung entwickelt wurde. Die Klasse berücksichtigt das Gebietsschema, die Zeitzone und den Kalender des Benutzers und gewährleistet so eine korrekte Anzeige von Daten in jeder Region der Welt. Laut Apple Developer Documentation (2025) unterstützt DateFormatter vier voreingestellte Datums- und Zeitstile sowie vollständig benutzerdefinierte Formate über eine Vorlagenzeichenfolge. Ohne DateFormatter ist es unmöglich, einem Benutzer in einer internationalisierten Anwendung ein Datum korrekt anzuzeigen.
Wichtige Erkenntnisse
DateFormatter ist eine Klasse aus dem Foundation-Framework, die die bidirektionale Konvertierung zwischen Date und Zeichenfolge implementiert. Sie erschien erstmals in OpenStep als NSDateFormatter und ist seitdem das wichtigste Werkzeug für die Datumsformatierung auf allen Apple-Plattformen. Die Klasse erbt von Formatter und bietet eine praktische API für die lokalisierte Datumsanzeige.
DateFormatter arbeitet auf der Grundlage von Unicode-LDML-Mustern — denselben, die in ICU (International Components for Unicode) verwendet werden. Das Muster wird über die dateFormat-Eigenschaft festgelegt, wobei die Symbole y, M, d, H, m, s für Jahr, Monat, Tag, Stunden, Minuten, Sekunden stehen. Die Wiederholung eines Symbols bestimmt das Format: „y“ — zweistelliges Jahr, „yyyy“ — vierstelliges Jahr.
Das Erstellen eines DateFormatter ist ein teurer Vorgang, da bei der Initialisierung Gebietsschema- und Kalenderdaten geladen werden. Apple empfiehlt, einen Formatierer einmal für jeden Formatierungstyp zu erstellen und wiederzuverwenden. In SwiftUI und UIKit werden Formatierer oft in statischen Eigenschaften zwischengespeichert oder beim ersten Zugriff verzögert erstellt.
DateFormatter wird in vielen iOS-Systemkomponenten verwendet. UIDatePicker verwendet DateFormatter intern zur Anzeige von Daten im countDownTimer-Modus. Ein TextField mit einem Formatierer kann automatisch vom Benutzer eingegebene Daten validieren. Core Data unterstützt Attribute vom Typ Date, deren Zeichenfolgendarstellung jedoch immer über DateFormatter erfolgt.
Thread-Sicherheit — DateFormatter ist nicht threadsicher. Das Ändern von Formatierereigenschaften aus verschiedenen Threads führt zu undefiniertem Verhalten. Für die Multithread-Verwendung erstellen Sie separate Formatiererinstanzen für jeden Thread oder verwenden Sie Synchronisierung über NSLock oder eine serielle Warteschlange.
dateStyle und timeStyle sind die einfachsten Möglichkeiten, die Datumsanzeige zu konfigurieren. Jeder Stil hat vier Varianten: .short, .medium, .long, .full. Die Kombination von dateStyle und timeStyle ermöglicht die unabhängige Konfiguration von Datums- und Zeitformat, und die Eigenschaft .none deaktiviert den entsprechenden Teil.
Für das US-amerikanische Gebietsschema formatiert .short das Datum als „7/21/26“, für das russische als „21.07.2026“. Der Stil .long gibt für das russische Gebietsschema „21. Juli 2026“ aus, und .full gibt „Dienstag, 21. Juli 2026“ mit dem Wochentag aus. Alle vier Stile passen sich automatisch an regionale Standards an, einschließlich der Reihenfolge der Komponenten und Trennzeichen.
SFDateFormatter in iOS 15+ bietet einen alternativen Ansatz über RelativeDateFormatter und DateIntervalFormatter. RelativeDateFormatter gibt „heute“, „gestern“, „in 3 Tagen“ für den aktuellen Kontext aus. DateIntervalFormatter zeigt Datumsbereiche an: „21.–25. Juli 2026“ — für Buchungen und Planung.
| Stil | Beispiel (ru_RU) | Beispiel (en_US) |
|---|---|---|
| .short | 21.07.2026 | 7/21/26 |
| .medium | 21. Juli 2026 | Jul 21, 2026 |
| .long | 21. Juli 2026 | July 21, 2026 |
| .full | Dienstag, 21. Juli 2026 | Tuesday, July 21, 2026 |
Beim Kombinieren von Stilen wählt DateFormatter automatisch das Trennzeichen: für .short.date + .short.time könnte das Ergebnis „21.07.2026, 14:30“ sein. Für .full.date + .full.time — „Dienstag, 21. Juli 2026, 14:30:00 MSK“. Das Trennzeichen wird vom Gebietsschema verwaltet, nicht vom Entwickler — dies gewährleistet die Übereinstimmung mit den regionalen Erwartungen des Benutzers.
dateFormat ermöglicht das Festlegen eines beliebigen Formatierungsmusters unter Verwendung von Unicode-LDML-Spezifikationssymbolen. Dies gibt volle Kontrolle über die Anzeige: Sie können nur Jahr und Monat anzeigen, oder den Wochentag ohne Datum, oder die Zeit ohne Sekunden. Benutzerdefiniertes Format ist für spezifische Designanforderungen unverzichtbar.
Hauptsymbole — yyyy (Jahr: 2026), MM (Monat: 07), dd (Tag: 21), HH (Stunden: 14), mm (Minuten: 30), ss (Sekunden: 00). Für den vollständigen Monatsnamen verwenden Sie MMMM (Juli), für die Kurzform — MMM (Jul). Wochentag — EEEE (Dienstag), Kurzform — E (Di).
Bei Verwendung von dateFormat ist es wichtig, das Gebietsschema des Formatierers festzulegen. Wenn kein locale festgelegt ist, verwendet der Formatierer das Systemgebietsschema, was für ein festes Format in einer API unerwünscht sein kann. Apple empfiehlt, locale = Locale(identifier: „en_US_POSIX“) für ein festes regionsübergreifendes Format festzulegen, insbesondere beim Parsen von Daten aus Serverantworten.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"
// Eine benutzerdefinierte Zeichenfolge parsen
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
Ein Fehler in dateFormat ist eine der häufigsten Ursachen für App-Abstürze. Wenn das Format nicht mit der Zeichenfolge übereinstimmt, gibt die Methode date(from:) nil zurück. Verwenden Sie guard let oder ?? für sicheres Auspacken von Optionals. Um das Format zu validieren, testen Sie es in allen unterstützten Sprachen — einige LDML-Symbole funktionieren in verschiedenen Gebietsschemata unterschiedlich.
Locale bestimmt, wie Monatsnamen, Wochentagsnamen und Trennzeichen angezeigt werden. DateFormatter verwendet standardmäßig Locale.current, aber in einigen Szenarien muss ein bestimmtes Gebietsschema angegeben werden: für ein festes Format in Protokollen verwenden Sie en_US_POSIX, für Serverdaten — das zum Server passende Gebietsschema.
Die Eigenschaft TimeZone bestimmt die Zeitzone für die Anzeige. Standardmäßig wird die Systemzeitzone verwendet, aber für Anwendungen mit internationalem Publikum müssen Daten oft in der Zeitzone des Benutzers oder in UTC angezeigt werden. Das Ändern von timeZone wirkt sich nur auf die Anzeige aus — der Date-Wert bleibt unverändert.
Eine wichtige Funktion: Wenn DateFormatter zum Parsen einer Zeichenfolge verwendet wird und die Zeichenfolge eine Zeitzonenangabe enthält (z. B. „2026-07-21T14:30:00Z“ mit Z für UTC), wird die timeZone-Eigenschaft ignoriert — der Formatierer verwendet die Zeitzone aus der Zeichenfolge. Wenn die Zeitzone in der Zeichenfolge fehlt, wird die timeZone des Formatierers angewendet.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
formatter.dateStyle = .long
formatter.timeStyle = .short
let moscowTime = formatter.string(from: Date())
// "21 July 2026, 14:30"
// Ohne Zeitzone in der Zeichenfolge parsen
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — ein spezieller Gebietsschematyp, der automatisch aktualisiert wird, wenn sich die Systemeinstellungen des Benutzers ändern. DateFormatter unterstützt dies standardmäßig. Wenn die App im Hintergrund läuft und der Benutzer die Systemsprache ändert, verwendet ein vor der Änderung erstellter Formatierer weiterhin das alte Gebietsschema — zum Aktualisieren muss eine neue Instanz erstellt werden.
ISO8601DateFormatter ist ein spezialisierter Formatierer für die Arbeit mit Daten im ISO-8601-Format. Dieses Format ist der De-facto-Standard für REST-APIs, JSON und Datenaustausch. ISO8601DateFormatter arbeitet deutlich schneller als DateFormatter, da es nicht von Gebietsschemata abhängt und eine feste Parsing-Grammatik verwendet.
Hauptoptionen des Formatierers — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (fügt Millisekunden hinzu), .withTimeZone (enthält Zeitzonenoffset). Durch Kombinieren von Optionen können Sie jede ISO-8601-Variante erhalten: mit Millisekunden, mit Zeitzone, nur mit Datum.
JSONEncoder.DateEncodingStrategy ermöglicht die globale Konfiguration der Datumscodierung für alle Codable-Modelle. Optionen — .iso8601 (verwendet ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Die Wahl der Strategie beeinflusst den gesamten Serialisierungslebenszyklus und sollte über alle API-Endpunkte hinweg konsistent sein.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// JSONEncoder mit ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Alternative: JSONEncoder mit benutzerdefiniertem Formatierer
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — wählen Sie ISO8601DateFormatter zum Serialisieren und Parsen von Daten in APIs, da es 5-10 Mal schneller ist als DateFormatter und nicht anfällig für Lokalisierungsfehler. Verwenden Sie DateFormatter für die Benutzeroberfläche, wo eine lokalisierte Anzeige mit Monats- und Tagesnamen in der Muttersprache des Benutzers erforderlich ist.
Betrachten wir reale Szenarien für die Verwendung von DateFormatter in einer iOS-App: Anzeige in einem Nachrichten-Feed, Eingabe eines Geburtsdatums und Export eines Berichts mit Daten in verschiedenen Zeitzonen.
RelativeDateFormatter ist optimal für Nachrichtenfeeds. Er zeigt „gerade eben“, „vor 5 Minuten“, „gestern“ für aktuelle Nachrichten an und wechselt für ältere zum vollständigen Datum. Die Umschaltschwelle wird über den Kalender konfiguriert: für Nachrichten verwenden Sie eine 24-Stunden-Schwelle, für Messenger — eine Woche.
func formatRelativeDate(_ date: Date) -> String {
let relative = RelativeDateFormatter()
relative.unitsStyle = .full
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let daysDiff = Calendar.current.dateComponents(
[.day], from: date, to: Date()
).day ?? 0
return daysDiff < 1
? relative.localizedString(for: date, relativeTo: Date())
: formatter.string(from: date)
}
Eingabe eines Geburtsdatums — ein weiteres häufiges Szenario. DateFormatter wird mit einem bestimmten dateFormat „dd.MM.yyyy“ und locale „ru_RU“ konfiguriert. Beim Parsen der eingegebenen Zeichenfolge ist es wichtig, mögliche Fehler zu behandeln: der Formatierer gibt nil für eine ungültige Zeichenfolge zurück. Nach erfolgreichem Parsen wird das Datum auf einen akzeptablen Bereich überprüft — nicht vor 1900, nicht nach heute.
Export eines Berichts mit Daten erfordert ein festes Format, das unabhängig vom Gebietsschema des Benutzers ist. Verwenden Sie dateFormat „yyyy-MM-dd HH:mm:ss“ mit locale en_US_POSIX und Zeitzone UTC. Dieser Ansatz garantiert, dass die Datei unabhängig von den regionalen Systemeinstellungen in jedem Land korrekt geöffnet wird.
| Szenario | Formatierer | Wichtige Einstellung |
|---|---|---|
| Nachrichten-Feed | RelativeDateFormatter | unitsStyle = .full |
| Datumeingabe | DateFormatter | dateFormat + Fallback |
| API-Serialisierung | ISO8601DateFormatter | withInternetDateTime |
| Berichtsexport | DateFormatter | en_US_POSIX + UTC |
Häufig gestellte Fragen
Der häufigste Grund — eine Nichtübereinstimmung zwischen dateFormat und dem Zeichenfolgenformat. Beispielsweise wird das Format „dd.MM.yyyy“ die Zeichenfolge „2026-07-21“ nicht parsen. Der zweite Grund — Nichtübereinstimmung des Gebietsschemas: die Zeichenfolge „July 21, 2026“ wird mit dem Gebietsschema ru_RU nicht geparst. Der dritte — Tippfehler in LDML-Symbolen: verwenden Sie yyyy, nicht YYYY (unterschiedliche Bedeutung).
Nein. DateFormatter ist ein schweres Objekt, dessen Initialisierung das Laden von Gebietsschemadaten umfasst. Erstellen Sie eine Instanz pro Formatierungstyp und verwenden Sie sie wieder. Verwenden Sie in einer Multithread-Umgebung Thread-lokalen Speicher oder einen Formatierer-Pool mit einer seriellen Warteschlange zur Synchronisierung.
DateFormatter zeigt ein absolutes Datum an (21. Juli 2026), während RelativeDateFormatter ein relatives Datum anzeigt (heute, gestern, in 3 Tagen). RelativeDateFormatter wurde in iOS 15+ eingeführt und verwendet dieselbe LDML-Vorlage, wählt aber automatisch die relative Anzeige aus.
Setzen Sie die timeZone des Formatierers vor dem Parsen auf UTC. Wenn der Server ein Datum in lokaler Zeit ohne Zeitzonenangabe zurückgibt, überprüfen Sie die API-Spezifikation — höchstwahrscheinlich ist UTC gemeint. Für ISO 8601 mit Z am Ende ist keine timeZone erforderlich — der Formatierer parst den Offset aus der Zeichenfolge.
Verwenden Sie keine einzelne Instanz aus verschiedenen Threads ohne Synchronisierung. Erstellen Sie eine neue Instanz in jedem Thread oder verwenden Sie Thread.current.threadDictionary zur Speicherung. Eine Alternative ist NSLock mit Sperrung für die Dauer von string(from:) und date(from:).
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch