DateFormatter — en Foundation-klass utformad för dubbelriktad konvertering mellan Date-objekt och deras strängrepresentation. Klassen tar hänsyn till användarens locale, tidszon och kalender, vilket säkerställer korrekt visning av datum i vilken region som helst i världen. Enligt Apple Developer Documentation (2025) stödjer DateFormatter fyra fördefinierade stilar för datum och tid, samt helt anpassade format genom en mallsträng. Utan DateFormatter är det inte möjligt att korrekt visa datum för användaren i en internationaliserad applikation.
Huvudsakligt
DateFormatter — en klass från Foundation-ramverket som implementerar dubbelriktad konvertering mellan Date och sträng. Den dök upp i OpenStep som NSDateFormatter och har sedan dess förblivit det främsta verktyget för datumformatering på alla Apple-plattformar. Klassen ärver från Formatter och tillhandahåller ett bekvämt API för lokaliserad datumvisning.
DateFormatterns arbetsprincip baseras på Unicode LDML-mallar — samma som används i ICU (International Components for Unicode). Mallen definieras genom egenskapen dateFormat, där symbolerna y, M, d, H, m, s motsvarar år, månad, dag, timmar, minuter och sekunder. Upprepning av symbolen bestämmer formatet: “y” — tvåsiffrigt år, “yyyy” — fyrsiffrigt.
Att skapa DateFormatter är en dyr operation, eftersom locale- och kalenderdata laddas vid initialisering. Apple rekommenderar att man skapar formatteraren en gång för varje formateringstyp och återanvänder den. I SwiftUI och UIKit cachas formatterare ofta i statiska egenskaper eller skapas lata vid första åtkomst.
DateFormatter används i många systemkomponenter i iOS. UIDatePicker använder internt DateFormatter för att visa datum i countDownTimer-läge. TextField med en formatterare vid inmatning kan automatiskt validera datumet som användaren anger. Core Data stödjer attribut av typen Date, men deras strängvisning sker alltid genom DateFormatter.
Thread Safety — DateFormatter är inte trådsäker. Ändring av formatterarens egenskaper från olika trådar leder till odefinierat beteende. För flertrådad användning, skapa separata formatterarinstanser för varje tråd eller använd synkronisering genom NSLock eller serial queue.
dateStyle och timeStyle — de enklaste sätten att konfigurera datumvisning. Varje stil har fyra varianter: .short, .medium, .long, .full. Kombinationen av dateStyle och timeStyle möjliggör oberoende konfiguration av datum- och tidsformat, och egenskapen .none inaktiverar motsvarande del.
För amerikansk locale formaterar .short datum som “7/21/26”, och för svensk — som “2026-07-21”. Stilen .long för svensk locale visar “21 juli 2026”, och .full — “tisdag 21 juli 2026” med veckodagsnamn. Alla fyra stilar anpassar sig automatiskt till regionala standarder, inklusive komponentordning och avgränsare.
RelativeDateFormatter i iOS 15+ erbjuder ett alternativt tillvägagångssätt genom RelativeDateFormatter och DateIntervalFormatter. RelativeDateFormatter visar “idag”, “igår”, “om 3 dagar” för aktuell kontext. DateIntervalFormatter visar datumintervall: “21–25 juli 2026” — för bokningar och planering.
| Stil | Exempel (sv_SE) | Exempel (en_US) |
|---|---|---|
| .short | 2026-07-21 | 7/21/26 |
| .medium | 21 juli 2026 | Jul 21, 2026 |
| .long | 21 juli 2026 | July 21, 2026 |
| .full | tisdag 21 juli 2026 | Tuesday, July 21, 2026 |
Vid kombination av stilar väljer DateFormatter automatiskt avgränsare: för .short.date + .short.time kan resultatet bli “2026-07-21, 14:30”. För .full.date + .full.time — “tisdag 21 juli 2026, 14:30:00 MSK”. Avgränsaren styrs av locale, inte av utvecklaren — detta garanterar överensstämmelse med användarens regionala förväntningar.
dateFormat låter dig definiera en godtycklig formateringsmall med hjälp av symbolerna i Unicode LDML-specifikationen. Detta ger full kontroll över visningen: du kan visa endast år och månad, veckodag utan siffra, eller tid utan sekunder. Anpassat format är oumbärligt för specifika designkrav.
Grundläggande symboler — yyyy (år: 2026), MM (månad: 07), dd (dag: 21), HH (timmar: 14), mm (minuter: 30), ss (sekunder: 00). För fullständigt månadsnamn använd MMMM (juli), för förkortat — MMM (jul). Veckodag — EEEE (tisdag), förkortad — E (ti).
När du använder dateFormat är det viktigt att ställa in formatterarens locale. Om locale inte är inställt använder formatteraren systemets locale, vilket kan vara oönskat för ett fast format i API. Apple rekommenderar att ställa in locale = Locale(identifier: “en_US_POSIX”) för ett fast interregionalt format, särskilt vid tolkning av datum från serversvar.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"
// Tolkning av anpassad sträng
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
Fel i dateFormat — en av de vanligaste orsakerna till appkraschar. Om formatet inte matchar strängen returnerar metoden date(from:) nil. Använd guard let eller ?? för säker extrahering av det optionella värdet. För validering av formatet, testa på alla språk — vissa LDML-symboler fungerar olika i olika locale.
Locale bestämmer hur månadsnamn, veckodagar och avgränsare visas. DateFormatter använder som standard Locale.current, men i vissa scenarier krävs specifik locale: för fast format i loggar använd en_US_POSIX, för serverdatum — locale identisk med servern.
Egenskapen TimeZone bestämmer tidszonen för visning. Som standard används systemets tidszon, men för applikationer med internationell publik krävs ofta visning i användarens tidszon eller i UTC. Ändring av timeZone påverkar endast visningen — Date-värdet förblir oförändrat.
En viktig egenskap: om DateFormatter används för tolkning av en sträng och strängen innehåller en tidszonsindikering (t.ex. “2026-07-21T14:30:00Z” med Z för UTC), ignoreras egenskapen timeZone — formatteraren använder tidszonen från strängen. Om tidszon saknas i strängen tillämpas formatterarens timeZone.
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"
// Tolkning utan tidszon i strängen
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — en speciell typ av locale som automatiskt uppdateras när användarens systeminställningar ändras. DateFormatter stödjer detta som standard. Om applikationen körs i bakgrunden och användaren ändrar systemets språk kommer formatteraren som skapades före ändringen att fortsätta använda gamla locale — för uppdatering måste en ny instans skapas.
ISO8601DateFormatter — en specialiserad formatterare för arbete med datum i ISO 8601-format. Detta format är de facto-standard för REST API, JSON och datautbyte. ISO8601DateFormatter fungerar betydligt snabbare än DateFormatter eftersom det inte är beroende av locale och använder en fast tolkningsgrammatik.
Formatterarens huvudalternativ — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (lägger till millisekunder), .withTimeZone (inkluderar tidszonsförskjutning). Genom att kombinera alternativ kan du få vilken ISO 8601-variant som helst: med millisekunder, med tidszon, med datum utan tid.
JSONEncoder.DateEncodingStrategy låter dig globalt konfigurera datumkodning för alla Codable-modeller. Varianter — .iso8601 (använder ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Val av strategi påverkar hela serialiseringslivscykeln och bör vara enhetlig för alla API-endpoints.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// JSONEncoder med ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Alternativ: JSONEncoder med anpassad formatterare
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — välj ISO8601DateFormatter för serialisering och tolkning av datum i API, eftersom det fungerar 5-10 gånger snabbare än DateFormatter och inte drabbas av lokaliseringsfel. Behåll DateFormatter för användargränssnittet där lokaliserad visning med månads- och veckodagsnamn på användarens modersmål krävs.
Låt oss titta på verkliga scenarier för användning av DateFormatter i en iOS-applikation: visning i nyhetslista, inmatning av födelsedatum och export av rapport med datum i olika tidszoner.
RelativeDateFormatter är optimalt för nyhetsflöden. Det visar “nyss”, “för 5 minuter sedan”, “igår” för färska nyheter och växlar till fullt datum för äldre. Växlingströskeln konfigureras via calendar: för nyheter använd en tröskel på 24 timmar, för meddelandeprogram — en vecka.
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)
}
Inmatning av födelsedatum — ytterligare ett vanligt scenario. DateFormatter konfigureras med specifik dateFormat “yyyy-MM-dd” och locale “sv_SE”. Vid tolkning av den inmatade strängen är det viktigt att hantera möjliga fel: formatteraren returnerar nil för ogiltig sträng. Efter lyckad tolkning kontrolleras datumet för att säkerställa att det ligger inom tillåtet intervall — inte tidigare än 1900, inte senare än idag.
Export av rapport med datum kräver ett fast format oberoende av användarens locale. Använd dateFormat “yyyy-MM-dd HH:mm:ss” med locale en_US_POSIX och tidszon UTC. Detta tillvägagångssätt garanterar att filen öppnas korrekt i vilket land som helst oavsett systemets regionala inställningar.
| Scenario | Formatterare | Nyckelinställning |
|---|---|---|
| Nyhetsflöde | RelativeDateFormatter | unitsStyle = .full |
| Datum inmatning | DateFormatter | dateFormat + fallback |
| API-serialisering | ISO8601DateFormatter | withInternetDateTime |
| Rapport export | DateFormatter | en_US_POSIX + UTC |
Vanliga frågor
Den vanligaste orsaken — att dateFormat inte matchar strängens format. Till exempel kommer formatet “yyyy-MM-dd” inte att tolka strängen “2026/07/21”. Andra orsaken — locale-mismatch: strängen “July 21, 2026” tolkas inte med locale sv_SE. Tredje — skrivfel i LDML-symboler: använd yyyy, inte YYYY (olika betydelse).
Nej. DateFormatter är ett tungt objekt, dess initialisering inkluderar inläsning av localedata. Skapa en instans per formateringstyp och återanvänd den. I en flertrådig miljö, använd Thread-local storage eller en pool av formatterare med serial queue för synkronisering.
DateFormatter visar absolut datum (21 juli 2026), medan RelativeDateFormatter visar relativt datum (idag, igår, om 3 dagar). RelativeDateFormatter kom i iOS 15+ och använder samma LDML-mall, men väljer automatiskt relativ visning.
Ställ in formatterarens timeZone till UTC före tolkning. Om servern returnerar datum i lokal tid utan tidszonsangivelse, kontrollera API-specifikationen — troligtvis avses UTC. För ISO 8601 med Z i slutet behövs ingen timeZone — formatteraren tolkar förskjutningen från strängen.
Använd inte en instans från olika trådar utan synkronisering. Skapa en ny instans i varje tråd eller använd Thread.current.threadDictionary för lagring. Alternativ — NSLock med låsning under string(from:) och date(from:).
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också