DateFormatter: concepte cheie, formatarea datei și localizare

Autor: IT Sectr Publicat: 2026-07-12 Timp de citire: 7 min

DateFormatter — o clasă Foundation concepută pentru conversia bidirecțională între obiectele Date și reprezentarea lor sub formă de șir. Clasa ia în considerare setările regionale, fusul orar și calendarul utilizatorului, asigurând afișarea corectă a datelor în orice regiune a lumii. Conform Apple Developer Documentation (2025), DateFormatter acceptă patru stiluri predefinite de dată și oră, precum și formate complet personalizate printr-un șablon. Fără DateFormatter nu este posibilă afișarea corectă a datei utilizatorului într-o aplicație internaționalizată.

Principalele

  • DateFormatter — clasă pentru conversia Date în șir și invers, cu luarea în considerare a setărilor regionale și a fusului orar.
  • dateStyle și timeStyle — stiluri predefinite (.short, .medium, .long, .full) pentru formatare rapidă.
  • dateFormat — șir șablon pentru format personalizat, definit prin simbolurile specificației Unicode LDML.
  • Locale și TimeZone — proprietăți ale formatorului care determină afișarea regională și fusul orar.
  • ISO8601DateFormatter — o alternativă mai rapidă pentru formatul ISO 8601 la serializarea în API.

Ce este DateFormatter?

DateFormatter — o clasă din framework-ul Foundation care implementează conversia bidirecțională între Date și șir. A apărut în OpenStep ca NSDateFormatter și de atunci rămâne principalul instrument de formatare a datelor pe toate platformele Apple. Clasa moștenește de la Formatter și oferă o API convenabilă pentru afișarea localizată a datelor.

Principiul de funcționare al DateFormatter se bazează pe șabloanele Unicode LDML — aceleași care sunt utilizate în ICU (International Components for Unicode). Șablonul este definit prin proprietatea dateFormat, unde simbolurile y, M, d, H, m, s corespund anului, lunii, zilei, orelor, minutelor și secundelor. Repetarea simbolului determină formatul: „y” — an cu două cifre, „yyyy” — cu patru cifre.

Crearea unui DateFormatter este o operație costisitoare, deoarece la inițializare se încarcă datele setărilor regionale și ale calendarului. Apple recomandă crearea formatorului o dată pentru fiecare tip de formatare și reutilizarea lui. În SwiftUI și UIKit, formatorii sunt adesea stocați în cache în proprietăți statice sau creați leneș la prima accesare.

DateFormatter în iOS SDK

DateFormatter este utilizat în multe componente de sistem iOS. UIDatePicker folosește intern DateFormatter pentru afișarea datelor în modul countDownTimer. TextField cu un formator la intrare poate valida automat data introdusă de utilizator. Core Data acceptă atribute de tip Date, dar afișarea lor ca text se face întotdeauna prin DateFormatter.

Thread Safety — DateFormatter nu este sigur pentru fire de execuție. Modificarea proprietăților formatorului din fire diferite duce la un comportament nedefinit. Pentru utilizare multi-thread, creați instanțe separate ale formatorului pentru fiecare fir sau utilizați sincronizarea prin NSLock sau serial queue.

Stiluri de formatare DateFormatter

dateStyle și timeStyle — cele mai simple moduri de a configura afișarea datei. Fiecare stil are patru variante: .short, .medium, .long, .full. Combinarea dateStyle și timeStyle permite configurarea independentă a formatului datei și orei, iar proprietatea .none dezactivează partea corespunzătoare.

Pentru setările regionale americane, stilul .short formatează data ca „7/21/26”, iar pentru cele românești — ca „21.07.2026”. Stilul .long pentru setările regionale românești afișează „21 iulie 2026”, iar .full — „marți, 21 iulie 2026” cu indicarea zilei săptămânii. Toate cele patru stiluri se adaptează automat la standardele regionale, inclusiv ordinea componentelor și separatoarele.

RelativeDateFormatter în iOS 15+ oferă o abordare alternativă prin RelativeDateFormatter și DateIntervalFormatter. RelativeDateFormatter afișează „azi”, „ieri”, „peste 3 zile” pentru contextul curent. DateIntervalFormatter arată intervale de date: “21–25 iulie 2026” — pentru rezervări și planificare.

StilExemplu (ro_RO)Exemplu (en_US)
.short21.07.20267/21/26
.medium21 iul. 2026Jul 21, 2026
.long21 iulie 2026July 21, 2026
.fullmarți, 21 iulie 2026Tuesday, July 21, 2026

La combinarea stilurilor, DateFormatter alege automat separatorul: pentru .short.date + .short.time rezultatul poate fi „21.07.2026, 14:30”. Pentru .full.date + .full.time — „marți, 21 iulie 2026, 14:30:00 MSK”. Separatorul este controlat de setările regionale, nu de dezvoltator — aceasta garantează conformitatea cu așteptările regionale ale utilizatorului.

Formate personalizate prin dateFormat

dateFormat permite definirea unui șablon arbitrar de formatare folosind simbolurile specificației Unicode LDML. Acest lucru oferă control total asupra afișării: puteți afișa doar anul și luna, ziua săptămânii fără număr sau ora fără secunde. Formatul personalizat este de neînlocuit pentru cerințele specifice de design.

Simbolurile de bază — yyyy (an: 2026), MM (lună: 07), dd (zi: 21), HH (ore: 14), mm (minute: 30), ss (secunde: 00). Pentru numele complet al lunii utilizați MMMM (iulie), pentru cel prescurtat — MMM (iul.). Ziua săptămânii — EEEE (marți), prescurtat — E (ma).

Când utilizați dateFormat, este important să setați locale formatorului. Dacă locale nu este setat, formatorul folosește setările regionale ale sistemului, ceea ce poate fi nedorit pentru un format fix în API. Apple recomandă setarea locale = Locale(identifier: “en_US_POSIX”) pentru un format inter-regional fix, în special la parsarea datelor din răspunsurile serverului.

swift
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"

// Parsarea unui șir personalizat
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!

Eroarea în dateFormat — una dintre cauzele frecvente ale crashes-ului aplicației. Dacă formatul nu se potrivește cu șirul, metoda date(from:) returnează nil. Utilizați guard let sau ?? pentru extragerea sigură a valorii opționale. Pentru validarea formatului, testați pe toate limbile acceptate — unele simboluri LDML funcționează diferit în diferite setări regionale.

Localizare și TimeZone

Locale determină cum sunt afișate numele lunilor, zilelor săptămânii și ce separatoare sunt utilizate. DateFormatter utilizează implicit Locale.current, dar în unele scenarii este necesară indicarea unor setări regionale specifice: pentru formatul fix în jurnal utilizați en_US_POSIX, pentru datele serverului — setări regionale identice cu cele ale serverului.

Proprietatea TimeZone determină fusul orar pentru afișare. Implicit se utilizează fusul orar al sistemului, dar pentru aplicațiile cu audiență internațională este adesea necesară afișarea datelor în fusul orar al utilizatorului sau în UTC. Modificarea timeZone afectează doar afișarea — valoarea Date rămâne neschimbată.

O caracteristică importantă: dacă DateFormatter este utilizat pentru parsarea unui șir, iar șirul conține o indicație a fusului orar (de exemplu, “2026-07-21T14:30:00Z” cu Z pentru UTC), proprietatea timeZone este ignorată — formatorul folosește fusul orar din șir. Dacă fusul orar lipsește din șir, se aplică timeZone formatorului.

swift
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"

// Parsare fără fus orar în șir
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!

AutoupdatingCurrentLocale — un tip special de setări regionale care se actualizează automat la modificarea setărilor de sistem ale utilizatorului. DateFormatter îl acceptă implicit. Dacă aplicația rulează în fundal și utilizatorul schimbă limba sistemului, formatorul creat înainte de modificare va continua să utilizeze setările regionale vechi — pentru actualizare este necesară crearea unei noi instanțe.

ISO8601DateFormatter și alternative

ISO8601DateFormatter — un formator specializat pentru lucrul cu datele în format ISO 8601. Acest format este standardul de facto pentru REST API, JSON și schimbul de date. ISO8601DateFormatter funcționează considerabil mai rapid decât DateFormatter, deoarece nu depinde de setările regionale și utilizează o gramatică fixă de parsare.

Opțiunile principale ale formatorului — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (adaugă milisecunde), .withTimeZone (include deplasarea fusului orar). Combinând opțiunile, puteți obține orice variantă ISO 8601: cu milisecunde, cu fus orar, cu dată fără oră.

JSONEncoder.DateEncodingStrategy vă permite să configurați global codificarea datelor pentru toate modelele Codable. Variante — .iso8601 (folosește ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Alegerea strategiei afectează întregul ciclu de viață al serializării și trebuie să fie uniformă pentru toate endpoint-urile API.

swift
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"

// JSONEncoder cu ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601

// Alternativă: JSONEncoder cu formator personalizat
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)

DateFormatter vs ISO8601DateFormatter — alegeți ISO8601DateFormatter pentru serializarea și parsarea datelor în API, deoarece funcționează de 5-10 ori mai rapid decât DateFormatter și nu este supus erorilor de localizare. Lăsați DateFormatter pentru interfața utilizator, unde este necesară afișarea localizată cu numele lunilor și zilelor săptămânii în limba maternă a utilizatorului.

Exemple de formatare a datelor

Să analizăm scenarii reale de utilizare a DateFormatter într-o aplicație iOS: afișarea într-o listă de știri, introducerea datei de naștere și exportul unui raport cu date în diferite fusuri orare.

Afișarea datei știrii în listă

RelativeDateFormatter este optim pentru fluxurile de știri. Acesta afișează „acum”, „acum 5 minute”, „ieri” pentru știri recente și comută la data completă pentru cele vechi. Pragul de comutare se configurează prin calendar: pentru știri utilizați un prag de 24 de ore, pentru mesagerie — o săptămână.

swift
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)
}

Introducerea datei de naștere — un alt scenariu frecvent. DateFormatter se configurează cu un dateFormat specific „dd.MM.yyyy” și setări regionale „ro_RO”. La parsarea șirului introdus, este important să tratați eventualele erori: formatorul returnează nil pentru un șir incorect. După parsarea reușită, data se verifică pentru încadrarea în intervalul permis — nu mai devreme de 1900, nu mai târziu de astăzi.

Exportul raportului cu date necesită un format fix, independent de setările regionale ale utilizatorului. Utilizați dateFormat „yyyy-MM-dd HH:mm:ss” cu setări regionale en_US_POSIX și fus orar UTC. Această abordare garantează că fișierul se va deschide corect în orice țară, indiferent de setările regionale ale sistemului.

ScenariuFormatorSetare cheie
Flux de știriRelativeDateFormatterunitsStyle = .full
Introducere datăDateFormatterdateFormat + fallback
Serializare APIISO8601DateFormatterwithInternetDateTime
Export raportDateFormatteren_US_POSIX + UTC

Întrebări frecvente

De ce DateFormatter returnează nil pentru un șir corect?

Cea mai frecventă cauză — nepotrivirea dateFormat cu formatul șirului. De exemplu, formatul „dd.MM.yyyy” nu va parsa șirul „2026-07-21”. A doua cauză — nepotrivirea setărilor regionale: șirul „July 21, 2026” nu se va parsa cu setările regionale ro_RO. A treia — greșeli în simbolurile LDML: utilizați yyyy, nu YYYY (sens diferit).

Este necesar să creez un nou DateFormatter pentru fiecare apel?

Nu. DateFormatter este un obiect greu, inițializarea sa include încărcarea datelor setărilor regionale. Creați o singură instanță pe tip de formatare și reutilizați-o. Într-un mediu multi-thread, utilizați Thread-local storage sau un pool de formatori cu o serial queue pentru sincronizare.

Cu ce diferă DateFormatter de RelativeDateFormatter?

DateFormatter afișează data absolută (21 iulie 2026), iar RelativeDateFormatter — data relativă (azi, ieri, peste 3 zile). RelativeDateFormatter a apărut în iOS 15+ și utilizează același șablon LDML, dar alege automat afișarea relativă.

Cum să gestionez datele fără fus orar din API?

Setați timeZone formatorului la UTC înainte de parsare. Dacă serverul returnează data în ora locală fără indicarea fusului, verificați specificația API — cel mai probabil se subînțelege UTC. Pentru ISO 8601 cu Z la sfârșit, timeZone nu este necesar — formatorul parsează deplasarea din șir.

Cum să fac DateFormatter thread-safe?

Nu utilizați o singură instanță din fire diferite fără sincronizare. Creați o nouă instanță în fiecare fir sau utilizați Thread.current.threadDictionary pentru stocare. Alternativă — NSLock cu blocare pe durata string(from:) și date(from:).

Rezumat

  • DateFormatter — clasă Foundation pentru conversia Date în șir și invers, cu luarea în considerare a setărilor regionale, fusului orar și calendarului utilizatorului.
  • Stilurile predefinite dateStyle și timeStyle cu variantele .short, .medium, .long, .full acoperă majoritatea scenariilor UI.
  • dateFormat personalizat prin simboluri LDML oferă control total asupra formatului, dar necesită atenție la localizare.
  • Locale și TimeZone — proprietăți obligatorii pentru afișarea corectă: pentru UI — setări regionale de sistem, pentru API — en_US_POSIX și UTC.
  • ISO8601DateFormatter — alegerea preferată pentru serializarea datelor în API datorită vitezei și stabilității.
  • DateFormatter nu este sigur pentru fire de execuție — utilizați instanțe separate pentru fiecare fir sau sincronizați accesul.
  • RelativeDateFormatter (iOS 15+) — soluția optimă pentru afișarea datelor relative în fluxurile de știri și mesagerie.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și