ISO8601DateFormatter ist eine Foundation-Klasse in iOS und macOS, die zum Formatieren und Parsen von Datumsangaben im internationalen Standard ISO 8601 entwickelt wurde. Laut Apple Developer Documentation, 2024 verarbeitet ISO8601DateFormatter automatisch Formate mit Millisekunden, Zeitzonen und Sekundenbruchteilen, ohne dass DateFormat manuell festgelegt werden muss. Im Gegensatz zu DateFormatter ist diese Klasse nicht von Locale und TimeZone abhängig — sie arbeitet streng nach der ISO 8601-Spezifikation, was sie ideal für den Austausch von Datumsangaben zwischen Server und Client macht. Die Klasse ist ab iOS 10 und macOS 10.12 verfügbar.
Wichtige Punkte
ISO8601DateFormatter ist eine spezialisierte Unterklasse von Formatter in Foundation, die die bidirektionale Konvertierung zwischen Date und ISO 8601-Formatzeichenfolgen implementiert. Der ISO 8601-Standard (International Standard for the Representation of Dates and Times) definiert ein internationales Format für den Austausch von Datums- und Zeitangaben: 2024-07-21T14:30:00+00:00. Im Gegensatz zu DateFormatter erfordert diese Klasse keine Angabe von dateFormat und bestimmt die Zeichenfolgenstruktur automatisch anhand der angegebenen Optionen.
Die Hauptvorteile von ISO8601DateFormatter gegenüber DateFormatter: keine Abhängigkeit vom Gebietsschema (Parsing funktioniert auf jedem Gerät identisch), integrierte Unterstützung für Sekundenbruchteile (mit beliebig vielen Dezimalstellen) und automatische Formaterkennung basierend auf den übergebenen Optionen. Die Klasse verarbeitet auch korrekt das Z-Suffix (UTC-Kennzeichnung), Zeitzonen im Format +HH:mm und reduzierte Genauigkeit (nur Datum ohne Uhrzeit).
Laut der ISO-Spezifikation (ISO 8601-1:2019) unterstützt der Standard vier Genauigkeitsstufen: Jahr (2024), Jahr-Monat (2024-07), vollständiges Datum (2024-07-21) und Datum-Uhrzeit mit Zeitzone (2024-07-21T14:30:00+00:00). ISO8601DateFormatter deckt alle diese Stufen durch eine Kombination von Formatoptionen ab und befreit den Entwickler von der manuellen Erstellung von dateFormat-Zeichenfolgen.
Das Funktionsprinzip von ISO8601DateFormatter basiert auf einer Kombination von Bit-Optionen (formatOptions), von denen jede eine bestimmte Datums- oder Zeitkomponente in die Ausgabe einbezieht. Beispielsweise enthält die Option .withFullDate Jahr, Monat und Tag; .withTime enthält Stunden, Minuten und Sekunden. Durch die Kombination von Optionen erhält der Entwickler die gewünschte Genauigkeitsstufe, ohne eine dateFormat-Zeichenfolge schreiben zu müssen.
Intern verwendet ISO8601DateFormatter die ICU-Bibliothek zum Parsen, jedoch mit festen ISO 8601-Regeln. Dies bedeutet, dass es die Locale- und TimeZone-Einstellungen auf dem Gerät ignoriert — das Ergebnis ist immer vorhersagbar. Zum Festlegen der Zeitzone wird die Eigenschaft timeZone verwendet, die standardmäßig UTC ist. Wenn timeZone auf nil gesetzt ist, wird die lokale Zeit des Geräts verwendet.
| Option | Beschreibung | Beispielausgabe |
|---|---|---|
| .withFullDate | Jahr, Monat, Tag | 2024-07-21 |
| .withTime | Stunden, Minuten, Sekunden | 14:30:00 |
| .withMilliseconds | Sekundenbruchteile (bis zu 3 Ziffern) | .123 |
| .withFractionalSeconds | Sekundenbruchteile (beliebige Genauigkeit) | .123456 |
| .withTimeZone | Zeitzone | +03:00 |
| .withColonSeparatorInTimeZone | Doppelpunkt-Trenner in Zeitzone | +03:00 (gegenüber +0300) |
| .withInternetDateTime | Vollständiges Format (Datum + Zeit + Zone) | 2024-07-21T14:30:00+00:00 |
Kombination von Optionen: .withInternetDateTime entspricht der Kombination von .withFullDate, .withTime und .withTimeZone. Zum Parsen von Zeichenfolgen mit Millisekunden fügen Sie .withFractionalSeconds hinzu. Es ist wichtig zu beachten, dass .withMilliseconds Sekundenbruchteile auf drei Ziffern begrenzt, während .withFractionalSeconds beliebige Genauigkeit unterstützt — von einer bis zu neun Ziffern nach dem Dezimalpunkt.
Die Formatoptionen von ISO8601DateFormatter sind in drei Gruppen unterteilt: Datumskomponenten (withFullDate, withYear, withMonth, withDay, withWeekOfYear), Zeitkomponenten (withTime, withHours, withMinutes, withSeconds) und zusätzliche Einstellungen (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Durch deren Kombination können Sie praktisch jedes ISO 8601-Unterformat erhalten.
Wichtige Nuance: .withFractionalSeconds und .withMilliseconds schließen sich gegenseitig aus — wenn beide gesetzt sind, wird .withFractionalSeconds angewendet. Zum Parsen von Millisekunden aus Serverdaten wird .withFractionalSeconds empfohlen, da viele Server Sekundenbruchteile mit drei, sechs oder neun Ziffern senden und .withFractionalSeconds jede Länge verarbeitet.
import Foundation
// Configure ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
// Different format option combinations
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Date: \(dateOnly)")
formatter.formatOptions = [.withFullDate, .withTime]
let dateTime = formatter.string(from: Date())
print("DateTime: \(dateTime)")
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let full = formatter.string(from: Date())
print("Full: \(full)")
// Parse string with milliseconds
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
print("Parsed: \(parsed)")
}
Grundlegende Verwendung von ISO8601DateFormatter beschränkt sich auf das Erstellen einer Instanz, das Festlegen von timeZone (UTC wird für Serverdaten empfohlen) und formatOptions, wonach string(from:) zum Formatieren und date(from:) zum Parsen aufgerufen werden kann. Im Gegensatz zu DateFormatter muss man sich keine Gedanken über Locale machen — die Klasse ignoriert regionale Einstellungen.
import Foundation
let formatter = ISO8601DateFormatter()
// Parse different ISO 8601 formats
let strings: [String] = [
"2024-07-21T14:30:00Z",
"2024-07-21T14:30:00+03:00",
"2024-07-21T14:30:00.123Z",
"2024-07-21"
]
for str in strings {
if let autoParsed = formatter.date(from: str) {
print("Parsed '\(str)': \(autoParsed)")
} else {
// Use withFullDate for date-only strings
formatter.formatOptions = [.withFullDate]
if let fallback = formatter.date(from: str) {
print("Fallback parsed '\(str)': \(fallback)")
}
formatter.formatOptions = [.withInternetDateTime]
}
}
// Serialize to RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")
Parsen von Datumsangaben mit Sekundenbruchteilen variabler Länge ist eine Funktion vieler moderner APIs. Ein Server kann entweder 2024-07-21T14:30:00.123Z (3 Ziffern) oder 2024-07-21T14:30:00.123456Z (6 Ziffern) senden. ISO8601DateFormatter mit der Option .withFractionalSeconds verarbeitet beide Varianten korrekt, während DateFormatter mit dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" nur dreistellige Millisekunden verarbeitet.
import Foundation
let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
.withInternetDateTime,
.withFractionalSeconds
]
// Different fractional second precision
let variants: [String] = [
"2024-07-21T14:30:00.1Z",
"2024-07-21T14:30:00.12Z",
"2024-07-21T14:30:00.123Z",
"2024-07-21T14:30:00.123456Z",
"2024-07-21T14:30:00.123456789Z"
]
for variant in variants {
if let parsed = variantFormatter.date(from: variant) {
print("OK: \(variant) -> \(parsed)")
} else {
print("FAIL: \(variant)")
}
}
// Use withMilliseconds (3 digits only)
variantFormatter.formatOptions = [
.withInternetDateTime,
.withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("With milliseconds: \(milliParsed)")
Testen des Parsens aller Varianten: der gezeigte Code demonstriert, dass ISO8601DateFormatter mit .withFractionalSeconds Sekundenbruchteile beliebiger Länge von 1 bis 9 Ziffern erfolgreich verarbeitet. Dies ist wichtig für die Kompatibilität mit verschiedenen Serverplattformen: .NET generiert oft 7 Ziffern (100-Nanosekunden-Ticks), Python — 6, Java — je nach Version 3 oder 9.
DateFormatter kann ebenfalls ISO 8601 parsen, erfordert jedoch die manuelle Konfiguration von dateFormat, locale und timeZone. Das Hauptproblem ist, dass DateFormatter von Locale abhängt und wenn en_US_POSIX nicht gesetzt ist, das Parsen für Benutzer aus Regionen mit nicht standardmäßigen Datumsformaten fehlschlagen kann. ISO8601DateFormatter löst dieses Problem auf Architekturebene: es verwendet Locale nicht.
| Parameter | ISO8601DateFormatter | DateFormatter |
|---|---|---|
| Locale-Konfiguration | Nicht erforderlich (ignoriert) | en_US_POSIX erforderlich |
| DateFormat | Automatisch (über Optionen) | Manuelle Formatzeichenfolge |
| Sekundenbruchteile | Beliebige Genauigkeit (.withFractionalSeconds) | Festes SSS |
| Z-Suffix | Wird korrekt verarbeitet | Über dateFormat |
| Leistung | Höher (spezialisiert) | Niedriger (allgemein) |
| Standard | Nur ISO 8601 | Jedes Format |
| iOS-Version | iOS 10+ | iOS 2+ |
Wann DateFormatter verwenden: wenn Sie ein Datum in einem Nicht-ISO-8601-Format formatieren müssen (z.B. „21. Juli 2024“ für die UI) oder wenn Sie iOS 9 und älter unterstützen müssen. Verwenden Sie für alle Server-Client-Datumsaustauschaufgaben ISO8601DateFormatter — es ist sicherer, leistungsfähiger und erfordert weniger Code. DateFormatter für ISO 8601 ist eine Quelle potenzieller Fehler im Zusammenhang mit Gebietsschema und regionalen Einstellungen.
Migration von DateFormatter zu ISO8601DateFormatter: Ersetzen Sie die Erstellung von DateFormatter + dateFormat + locale + timeZone durch die Erstellung von ISO8601DateFormatter + formatOptions + timeZone. Das Parsen der Zeichenfolge bleibt über date(from:) unverändert. Für Abwärtskompatibilität können Sie #available(iOS 10, *) mit einem Fallback auf DateFormatter verwenden.
Vergessene formatOptions-Konfiguration führt dazu, dass der Formatierer den Standardwert — .withInternetDateTime — verwendet. Wenn der Server ein Datum ohne Uhrzeit sendet (2024-07-21), gibt das Parsen nil zurück. Überprüfen Sie immer, ob formatOptions alle möglichen Formate abdeckt, die vom Server kommen können. Verwenden Sie für APIs mit variablen Formaten Fallback-Versuche mit verschiedenen Optionskombinationen.
Verwechslung von withMilliseconds und withFractionalSeconds ist ein häufiger Fehler beim Parsen von Datumsangaben mit Sekundenbruchteilen. withMilliseconds erwartet genau 3 Ziffern nach dem Dezimalpunkt. Wenn der Server 6 Ziffern (Mikrosekunden) sendet, schlägt das Parsen mit withMilliseconds fehl. Verwenden Sie .withFractionalSeconds für die Kompatibilität mit einer beliebigen Anzahl von Ziffern. .withFractionalSeconds wurde in iOS 13 eingeführt; für ältere Versionen verwenden Sie DateFormatter mit dateFormat.
Ignorieren der Zeitzone ist ein weiteres häufiges Problem. Wenn der Server ein Datum mit Zeitzone (+03:00) sendet und der Formatierer auf UTC eingestellt ist, schlägt das Parsen nicht fehl, aber das Ergebnis liegt in UTC vor. Entwickler erwarten oft, dass Date die Zeitzone beibehält, aber Date ist ein absoluter Zeitpunkt — es speichert keine Zeitzoneninformationen. Für die korrekte Anzeige speichern Sie die Zeitzone separat oder verwenden Sie ISO8601DateFormatter mit der richtigen timeZone.
Laut Apple Forum (2024) betreffen etwa 20% der Fragen zu ISO8601DateFormatter das Format, bei dem Sekunden optional sind. Der ISO 8601-Standard erlaubt ein Format ohne Sekunden: 2024-07-21T14:30+03:00. ISO8601DateFormatter mit .withInternetDateTime unterstützt dieses Format nicht — zum Parsen ist DateFormatter mit dateFormat = "yyyy-MM-dd'T'HH:mmZ" erforderlich. Diese Einschränkung ist bei der Arbeit mit APIs zu beachten, die das verkürzte Zeitformat verwenden.
Häufig gestellte Fragen
ISO8601DateFormatter ist eine spezialisierte Foundation-Klasse zum Formatieren und Parsen von Datumsangaben im ISO 8601-Format, verfügbar ab iOS 10. Verarbeitet automatisch Standardformate ohne manuelles Festlegen von dateFormat.
ISO8601DateFormatter ist nicht von Locale abhängig, verwendet Optionen statt dateFormat und verarbeitet Sekundenbruchteile beliebiger Länge korrekt. DateFormatter ist universell, erfordert jedoch manuelle Konfiguration und ist anfällig für Fehler im Zusammenhang mit regionalen Einstellungen.
Verwenden Sie die Option .withFractionalSeconds — sie unterstützt 1 bis 9 Ziffern nach dem Dezimalpunkt. Verwenden Sie nicht .withMilliseconds, wenn die Genauigkeit variieren kann. .withFractionalSeconds ist ab iOS 13 verfügbar.
Standardmäßig UTC. Zum Ändern setzen Sie die Eigenschaft timeZone. Wenn timeZone = nil ist, wird die lokale Zeit des Geräts verwendet. Beim Parsen einer Zeichenfolge mit expliziter Zeitzone im Format +HH:MM berücksichtigt der Formatierer diese automatisch.
Weil formatOptions standardmäßig .withInternetDateTime ist, das Datum + Uhrzeit + Zeitzone erwartet. Zum Parsen nur des Datums setzen Sie formatOptions = [.withFullDate]. Um beide Varianten zu unterstützen, verwenden Sie Fallback mit verschiedenen Optionen.
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