ISO8601DateFormatter — je třída Foundation v iOS a macOS, určená pro formátování a parsování dat v mezinárodním standardu ISO 8601. Podle Apple Developer Documentation, 2024, ISO8601DateFormatter automaticky zpracovává formáty s milisekundami, časovými pásmy a zlomky sekund bez nutnosti ručně nastavovat DateFormat. Na rozdíl od DateFormatter tato třída není závislá na Locale a TimeZone — pracuje přísně podle specifikace ISO 8601, což ji činí ideální pro výměnu dat mezi serverem a klientem. Třída je dostupná od iOS 10 a macOS 10.12.
Hlavní body
ISO8601DateFormatter — je specializovaná podtřída Formatter ve Foundation, která implementuje obousměrnou konverzi mezi Date a řetězcem ve formátu ISO 8601. Standard ISO 8601 (International Standard for the Representation of Dates and Times) definuje mezinárodní formát pro výměnu dat a času: 2024-07-21T14:30:00+00:00. Na rozdíl od DateFormatter tato třída nevyžaduje zadání dateFormat a automaticky určuje strukturu řetězce na základě daných možností.
Hlavní výhody ISO8601DateFormatter oproti DateFormatter: absence závislosti na locale (parsování funguje stejně na jakémkoli zařízení), vestavěná podpora zlomků sekund (s libovolným počtem desetinných míst) a automatické určení formátu na základě předaných možností. Třída také správně zpracovává příponu Z (označení UTC), časová pásma ve formátu +HH:mm a sníženou přesnost (pouze datum bez času).
Podle ISO Specification (ISO 8601-1:2019) standard podporuje čtyři úrovně přesnosti: rok (2024), rok-měsíc (2024-07), plné datum (2024-07-21) a datum-čas s časovým pásmem (2024-07-21T14:30:00+00:00). ISO8601DateFormatter pokrývá všechny tyto úrovně kombinací možností formátu a zbavuje vývojáře nutnosti ručně konstruovat řetězec dateFormat.
Princip fungování ISO8601DateFormatter je založen na kombinaci bitových možností (formatOptions), z nichž každá aktivuje určitou komponentu data nebo času ve výstupu. Například možnost .withFullDate aktivuje rok, měsíc a den; .withTime — hodiny, minuty a sekundy. Kombinováním možností získá vývojář požadovanou úroveň přesnosti bez psaní řetězce dateFormat.
Interně ISO8601DateFormatter používá knihovnu ICU pro parsování, ale s pevnými pravidly ISO 8601. To znamená, že ignoruje nastavení Locale a TimeZone nainstalovaná na zařízení — výsledek je vždy předvídatelný. Pro nastavení časového pásma se používá vlastnost timeZone, která je ve výchozím nastavení rovna UTC. Pokud je timeZone nastaven na nil, použije se místní čas zařízení.
| Možnost | Popis | Příklad výstupu |
|---|---|---|
| .withFullDate | Rok, měsíc, den | 2024-07-21 |
| .withTime | Hodiny, minuty, sekundy | 14:30:00 |
| .withMilliseconds | Zlomky sekund (až 3 znaky) | .123 |
| .withFractionalSeconds | Zlomky sekund (libovolná přesnost) | .123456 |
| .withTimeZone | Časové pásmo | +03:00 |
| .withColonSeparatorInTimeZone | Oddělovač : v časovém pásmu | +03:00 (místo +0300) |
| .withInternetDateTime | Plný formát (date + time + tz) | 2024-07-21T14:30:00+00:00 |
Kombinování možností: .withInternetDateTime je ekvivalentní kombinaci .withFullDate, .withTime a .withTimeZone. Pro parsování řetězců s milisekundami přidejte .withFractionalSeconds. Je důležité si zapamatovat, že .withMilliseconds omezuje zlomky sekund na tři znaky, zatímco .withFractionalSeconds podporuje libovolnou přesnost — od jedné do devíti číslic za desetinnou čárkou.
Možnosti formátu ISO8601DateFormatter jsou rozděleny do tří skupin: komponenty data (withFullDate, withYear, withMonth, withDay, withWeekOfYear), komponenty času (withTime, withHours, withMinutes, withSeconds) a doplňková nastavení (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Jejich kombinací lze získat prakticky libovolný podformát ISO 8601.
Důležitý detail: .withFractionalSeconds a .withMilliseconds se vzájemně vylučují — pokud jsou nastaveny obě, použije se .withFractionalSeconds. Pro parsování milisekund ze serverových dat se doporučuje .withFractionalSeconds, protože mnoho serverů posílá zlomky sekund se třemi, šesti nebo devíti znaky a .withFractionalSeconds zpracovává libovolnou délku.
import Foundation
// Nakonfiguruj ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
// Různé kombinace možností formátu
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Datum: \(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("Plný: \(full)")
// Parsuj řetězec s milisekundami
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
print("Parsováno: \(parsed)")
}
Základní použití ISO8601DateFormatter spočívá ve vytvoření instance, nastavení timeZone (doporučuje se UTC pro serverová data) a formatOptions, poté lze volat string(from:) pro formátování a date(from:) pro parsování. Na rozdíl od DateFormatter se nemusíte starat o Locale — třída ignoruje regionální nastavení.
import Foundation
let formatter = ISO8601DateFormatter()
// Parsuj různé formáty ISO 8601
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("Parsováno '\(str)': \(autoParsed)")
} else {
// Použij withFullDate pro řetězce pouze s datem
formatter.formatOptions = [.withFullDate]
if let fallback = formatter.date(from: str) {
print("Fallback parsováno '\(str)': \(fallback)")
}
formatter.formatOptions = [.withInternetDateTime]
}
}
// Serializuj do RFC 3339 (API GitHub)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")
Parsování dat s zlomkovými sekundami proměnlivé délky — vlastnost mnoha moderních API. Server může odeslat jak 2024-07-21T14:30:00.123Z (3 znaky), tak 2024-07-21T14:30:00.123456Z (6 znaků). ISO8601DateFormatter s možností .withFractionalSeconds správně zpracuje obě varianty, zatímco DateFormatter s dateFormat = „yyyy-MM-dd’T’HH:mm:ss.SSSZ” zpracuje pouze tříciferné milisekundy.
import Foundation
let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
.withInternetDateTime,
.withFractionalSeconds
]
// Různá přesnost zlomkových sekund
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)")
}
}
// Použij withMilliseconds (pouze 3 číslice)
variantFormatter.formatOptions = [
.withInternetDateTime,
.withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("S milisekundami: \(milliParsed)")
Testování parsování všech variant: výše uvedený kód ukazuje, že ISO8601DateFormatter s .withFractionalSeconds úspěšně zpracovává zlomky sekund libovolné délky od 1 do 9 znaků. To je důležité pro kompatibilitu s různými serverovými platformami: .NET často generuje 7 znaků (100-nanosekundové ticky), Python — 6, Java — 3 nebo 9 v závislosti na verzi.
DateFormatter také umí parsovat ISO 8601, ale vyžaduje ruční nastavení dateFormat, locale a timeZone. Hlavním problémem je, že DateFormatter závisí na Locale, a pokud není nastaven en_US_POSIX, parsování se může pokazit u uživatelů z regionů s nestandardními formáty dat. ISO8601DateFormatter řeší tento problém na úrovni architektury: Locale nepoužívá.
| Parametr | ISO8601DateFormatter | DateFormatter |
|---|---|---|
| Nastavení Locale | Není vyžadováno (ignoruje) | en_US_POSIX povinné |
| DateFormat | Automatický (přes možnosti) | Ruční řetězec format |
| Zlomkové sekundy | Libovolná přesnost (.withFractionalSeconds) | Pevný SSS |
| Přípona Z | Správně zpracovává | Přes dateFormat |
| Výkon | Vyšší (specializovaný) | Nižší (obecný) |
| Standard | Pouze ISO 8601 | Libovolný formát |
| Verze iOS | iOS 10+ | iOS 2+ |
Kdy použít DateFormatter: pokud potřebujete formátovat datum v ne-ISO 8601 formátu (například „21. července 2024” pro UI) nebo pokud je vyžadována podpora iOS 9 a starších. Pro všechny úkoly výměny dat se serverem použijte ISO8601DateFormatter — je bezpečnější, výkonnější a vyžaduje méně kódu. DateFormatter pro ISO 8601 je zdrojem potenciálních chyb souvisejících s locale a regionálním nastavením.
Migrace z DateFormatter na ISO8601DateFormatter: nahraďte vytvoření DateFormatter + nastavení dateFormat + locale + timeZone vytvořením ISO8601DateFormatter + nastavením formatOptions + timeZone. Parsování řetězce zůstává nezměněno přes date(from:). Pro zpětnou kompatibilitu lze použít #available(iOS 10, *) s fallbackem na DateFormatter.
Zapomenuté nastavení formatOptions způsobí, že formatter použije výchozí hodnotu — .withInternetDateTime. Pokud server posílá pouze datum bez času (2024-07-21), parsování vrátí nil. Vždy zkontrolujte, že formatOptions pokrývají všechny možné formáty, které mohou ze serveru přijít. Pro API s proměnlivými formáty použijte fallback pokusy s různými kombinacemi možností.
Záměna withMilliseconds a withFractionalSeconds — častá chyba při parsování dat se zlomky sekund. withMilliseconds očekává přesně 3 číslice za desetinnou čárkou. Pokud server pošle 6 číslic (mikrosekundy), parsování s withMilliseconds selže. Použijte .withFractionalSeconds pro kompatibilitu s libovolným počtem znaků. .withFractionalSeconds se objevil v iOS 13; pro starší verze použijte DateFormatter s dateFormat.
Ignorování časového pásma — další častý problém. Pokud server posílá datum s časovým pásmem (+03:00) a formatter je nastaven na UTC, parsování neselže, ale výsledek bude v UTC. Vývojáři často očekávají, že Date zachová časové pásmo, ale Date je absolutní okamžik v čase a neukládá informace o časovém pásmu. Pro správné zobrazení uložte časové pásmo zvlášť nebo použijte ISO8601DateFormatter se správným timeZone.
Podle Apple Forum (2024) se asi 20% dotazů týkajících se ISO8601DateFormatter týká formátu, kde jsou sekundy volitelné. Standard ISO 8601 povoluje formát bez sekund: 2024-07-21T14:30+03:00. ISO8601DateFormatter s .withInternetDateTime tento formát nepodporuje — pro jeho parsování je zapotřebí DateFormatter s dateFormat = „yyyy-MM-dd’T’HH:mmZ”. Toto omezení je třeba vzít v úvahu při práci s API, která používají zkrácený formát času.
Často kladené otázky
ISO8601DateFormatter — specializovaná třída Foundation pro formátování a parsování dat ve formátu ISO 8601, dostupná od iOS 10. Automaticky zpracovává standardní formáty bez ručního zadání dateFormat.
ISO8601DateFormatter není závislý na Locale, používá možnosti místo dateFormat a správně zpracovává zlomky sekund libovolné délky. DateFormatter je univerzální, ale vyžaduje ruční konfiguraci a je náchylný k chybám souvisejícím s regionálním nastavením.
Použijte možnost .withFractionalSeconds — podporuje 1 až 9 znaků za desetinnou čárkou. Nepoužívejte .withMilliseconds, pokud se přesnost může měnit. .withFractionalSeconds je dostupný od iOS 13.
Výchozí je UTC. Pro změnu nastavte vlastnost timeZone. Pokud je timeZone = nil, použije se místní čas zařízení. Při parsování řetězce s explicitním časovým pásmem ve formátu +HH:MM jej formatter automaticky zohlední.
Protože výchozí formatOptions = .withInternetDateTime, který očekává datum + čas + časové pásmo. Pro parsování pouze data nastavte formatOptions = [.withFullDate]. Pro podporu obou variant použijte fallback s různými možnostmi.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také