DateFormatter — třída Foundation navržená pro obousměrnou konverzi mezi objekty Date a jejich řetězcovou reprezentací. Třída bere v úvahu místní nastavení, časové pásmo a kalendář uživatele, čímž zajišťuje správné zobrazení dat v jakémkoli regionu světa. Podle Apple Developer Documentation (2025) DateFormatter podporuje čtyři předdefinované styly data a času, stejně jako zcela vlastní formáty pomocí řetězce vzoru. Bez DateFormatteru není možné správně zobrazit datum uživateli v internacionalizované aplikaci.
Hlavní
DateFormatter — třída z frameworku Foundation, která implementuje obousměrnou konverzi mezi Date a řetězcem. Objevila se v OpenStep jako NSDateFormatter a od té doby zůstává hlavním nástrojem pro formátování dat na všech platformách Apple. Třída dědí z Formatter a poskytuje pohodlné API pro lokalizované zobrazení dat.
Princip fungování DateFormatter je založen na vzorech Unicode LDML — stejných, které se používají v ICU (International Components for Unicode). Vzor je definován vlastností dateFormat, kde symboly y, M, d, H, m, s odpovídají roku, měsíci, dni, hodinám, minutám a sekundám. Opakování symbolu určuje formát: „y“ — dvoumístný rok, „yyyy“ — čtyřmístný.
Vytvoření DateFormatter je nákladná operace, protože při inicializaci se načítají data místního nastavení a kalendáře. Apple doporučuje vytvořit formátovač jednou pro každý typ formátování a znovu jej používat. V SwiftUI a UIKit jsou formátovače často ukládány do mezipaměti ve statických vlastnostech nebo vytvářeny líně při prvním přístupu.
DateFormatter se používá v mnoha systémových komponentách iOS. UIDatePicker interně používá DateFormatter k zobrazení dat v režimu countDownTimer. TextField s formátovačem na vstupu může automaticky validovat datum zadané uživatelem. Core Data podporuje atributy typu Date, ale jejich řetězcové zobrazení se vždy provádí prostřednictvím DateFormatter.
Thread Safety — DateFormatter není vláknově bezpečný. Změna vlastností formátovače z různých vláken vede k nedefinovanému chování. Pro vícevláknové použití vytvářejte samostatné instance formátovače pro každé vlákno nebo použijte synchronizaci pomocí NSLock nebo serial queue.
dateStyle a timeStyle — nejjednodušší způsoby konfigurace zobrazení data. Každý styl má čtyři varianty: .short, .medium, .long, .full. Kombinace dateStyle a timeStyle umožňuje nezávisle konfigurovat formát data a času a vlastnost .none vypne příslušnou část.
Pro americké místní nastavení formátuje .short datum jako „7/21/26“, pro české — jako „21.07.2026“. Styl .long pro české místní nastavení zobrazuje „21. července 2026“, a .full — „úterý 21. července 2026“ s uvedením dne v týdnu. Všechny čtyři styly se automaticky přizpůsobují regionálním standardům, včetně pořadí komponent a oddělovačů.
RelativeDateFormatter v iOS 15+ nabízí alternativní přístup prostřednictvím RelativeDateFormatter a DateIntervalFormatter. RelativeDateFormatter zobrazuje „dnes“, „včera“, „za 3 dny“ pro aktuální kontext. DateIntervalFormatter zobrazuje rozsahy dat: “21.–25. července 2026” — pro rezervace a plánování.
| Styl | Příklad (cs_CZ) | Příklad (en_US) |
|---|---|---|
| .short | 21.07.2026 | 7/21/26 |
| .medium | 21. 7. 2026 | Jul 21, 2026 |
| .long | 21. července 2026 | July 21, 2026 |
| .full | úterý 21. července 2026 | Tuesday, July 21, 2026 |
Při kombinování stylů DateFormatter automaticky vybírá oddělovač: pro .short.date + .short.time může být výsledek „21.07.2026, 14:30“. Pro .full.date + .full.time — „úterý 21. července 2026, 14:30:00 MSK“. Oddělovač je řízen místním nastavením, nikoli vývojářem — to zaručuje soulad s regionálními očekáváními uživatele.
dateFormat umožňuje definovat libovolný vzor formátování pomocí symbolů specifikace Unicode LDML. To poskytuje úplnou kontrolu nad zobrazením: můžete zobrazit pouze rok a měsíc, den v týdnu bez čísla nebo čas bez sekund. Vlastní formát je nepostradatelný pro specifické požadavky designu.
Základní symboly — yyyy (rok: 2026), MM (měsíc: 07), dd (den: 21), HH (hodiny: 14), mm (minuty: 30), ss (sekundy: 00). Pro plný název měsíce použijte MMMM (červenec), pro zkrácený — MMM (čvc). Den v týdnu — EEEE (úterý), zkráceně — E (út).
Při použití dateFormat je důležité nastavit locale formátovače. Pokud locale není nastaveno, formátovač použije systémové místní nastavení, což může být nežádoucí pro pevný formát v API. Apple doporučuje nastavit locale = Locale(identifier: “en_US_POSIX”) pro pevný mezinárodní formát, zejména při parsování dat ze serverových odpovědí.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"
// Analýza vlastního řetězce
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
Chyba v dateFormat — jeden z častých důvodů pádu aplikace. Pokud formát neodpovídá řetězci, metoda date(from:) vrací nil. Použijte guard let nebo ?? pro bezpečné získání volitelné hodnoty. Pro validaci formátu testujte na všech podporovaných jazycích — některé symboly LDML fungují v různých místních nastaveních odlišně.
Locale určuje, jak se zobrazují názvy měsíců, dnů v týdnu a jaké oddělovače se používají. DateFormatter ve výchozím nastavení používá Locale.current, ale v některých scénářích je třeba zadat konkrétní místní nastavení: pro pevný formát v logech použijte en_US_POSIX, pro serverová data — místní nastavení shodné se serverem.
Vlastnost TimeZone určuje časové pásmo pro zobrazení. Ve výchozím nastavení se používá systémové časové pásmo, ale pro aplikace s mezinárodním publikem je často nutné zobrazovat data v časovém pásmu uživatele nebo v UTC. Změna timeZone ovlivňuje pouze zobrazení — hodnota Date zůstává nezměněná.
Důležitá vlastnost: pokud je DateFormatter použit pro parsování řetězce a řetězec obsahuje označení časového pásma (např. “2026-07-21T14:30:00Z” s Z pro UTC), vlastnost timeZone je ignorována — formátovač použije časové pásmo z řetězce. Pokud časové pásmo v řetězci chybí, použije se timeZone formátovače.
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"
// Analýza bez časového pásma v řetězci
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — speciální typ místního nastavení, které se automaticky aktualizuje při změně systémových nastavení uživatele. DateFormatter jej ve výchozím nastavení podporuje. Pokud aplikace běží na pozadí a uživatel změní jazyk systému, formátovač vytvořený před změnou bude nadále používat staré místní nastavení — pro aktualizaci je třeba vytvořit novou instanci.
ISO8601DateFormatter — specializovaný formátovač pro práci s daty ve formátu ISO 8601. Tento formát je de facto standardem pro REST API, JSON a výměnu dat. ISO8601DateFormatter pracuje výrazně rychleji než DateFormatter, protože nezávisí na místním nastavení a používá pevnou gramatiku parsování.
Hlavní volby formátovače — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (přidává milisekundy), .withTimeZone (zahrnuje posun časového pásma). Kombinováním voleb lze získat libovolnou variantu ISO 8601: s milisekundami, s časovým pásmem, s datem bez času.
JSONEncoder.DateEncodingStrategy umožňuje globálně konfigurovat kódování dat pro všechny modely Codable. Varianty — .iso8601 (používá ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Výběr strategie ovlivňuje celý životní cyklus serializace a měl by být jednotný pro všechny API endpointy.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// JSONEncoder s ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Alternativa: JSONEncoder s vlastním formátovačem
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — vybírejte ISO8601DateFormatter pro serializaci a parsování dat v API, protože pracuje 5-10 krát rychleji než DateFormatter a není náchylný k chybám lokalizace. DateFormatter ponechte pro uživatelské rozhraní, kde je vyžadováno lokalizované zobrazení s názvy měsíců a dnů v týdnu v rodném jazyce uživatele.
Podívejme se na reálné scénáře použití DateFormatter v aplikaci pro iOS: zobrazení v seznamu novinek, zadání data narození a export sestavy s daty v různých časových pásmech.
RelativeDateFormatter je optimální pro zpravodajské kanály. Zobrazuje „právě teď“, „před 5 minutami“, „včera“ pro čerstvé zprávy a přepíná na plné datum pro starší. Práh přepínání se konfiguruje pomocí calendar: pro zprávy použijte práh 24 hodin, pro messenger — týden.
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)
}
Zadání data narození — další častý scénář. DateFormatter se konfiguruje s konkrétním dateFormat „dd.MM.yyyy“ a místním nastavením „cs_CZ“. Při parsování zadaného řetězce je důležité ošetřit možné chyby: formátovač vrací nil pro neplatný řetězec. Po úspěšném parsování se datum zkontroluje, zda spadá do povoleného rozsahu — ne dříve než 1900, ne později než dnes.
Export sestavy s daty vyžaduje pevný formát nezávislý na místním nastavení uživatele. Použijte dateFormat „yyyy-MM-dd HH:mm:ss“ s místním nastavením en_US_POSIX a časovým pásmem UTC. Tento přístup zaručuje, že se soubor správně otevře v jakékoli zemi bez ohledu na regionální nastavení systému.
| Scénář | Formátovač | Klíčové nastavení |
|---|---|---|
| Zpravodajský kanál | RelativeDateFormatter | unitsStyle = .full |
| Zadání data | DateFormatter | dateFormat + fallback |
| API serializace | ISO8601DateFormatter | withInternetDateTime |
| Export sestavy | DateFormatter | en_US_POSIX + UTC |
Často kladené dotazy
Nejčastější příčina — nesoulad dateFormat s formátem řetězce. Například formát „dd.MM.yyyy“ neparsuje řetězec „2026-07-21“. Druhý důvod — nesoulad místního nastavení: řetězec „July 21, 2026“ se neparsuje s místním nastavením cs_CZ. Třetí — překlepy v symbolech LDML: používejte yyyy, nikoli YYYY (odlišný význam).
Ne. DateFormatter je těžký objekt, jeho inicializace zahrnuje načítání dat místního nastavení. Vytvořte jednu instanci na typ formátování a znovu ji používejte. V multithreadovém prostředí použijte Thread-local storage nebo fond formátovačů s serial queue pro synchronizaci.
DateFormatter zobrazuje absolutní datum (21. července 2026), zatímco RelativeDateFormatter — relativní datum (dnes, včera, za 3 dny). RelativeDateFormatter se objevil v iOS 15+ a používá stejný vzor LDML, ale automaticky volí relativní zobrazení.
Nastavte timeZone formátovače na UTC před parsováním. Pokud server vrací datum v místním čase bez označení pásma, zkontrolujte specifikaci API — pravděpodobně se předpokládá UTC. Pro ISO 8601 s Z na konci timeZone není potřeba — formátovač parsuje posun z řetězce.
Nepoužívejte jednu instanci z různých vláken bez synchronizace. Vytvářejte novou instanci v každém vlákně nebo použijte Thread.current.threadDictionary pro uložení. Alternativa — NSLock s uzamčením po dobu string(from:) a date(from:).
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é