ISO8601DateFormatter — är en Foundation-klass i iOS och macOS, avsedd för formatering och tolkning av datum i den internationella standarden ISO 8601. Enligt Apple Developer Documentation, 2024, hanterar ISO8601DateFormatter automatiskt format med millisekunder, tidszoner och bråkdelar av sekunder utan att man behöver ställa in DateFormat manuellt. Till skillnad från DateFormatter är denna klass inte beroende av Locale och TimeZone — den arbetar strikt enligt ISO 8601-specifikationen, vilket gör den idealisk för utbyte av datum mellan server och klient. Klassen är tillgänglig från iOS 10 och macOS 10.12.
Huvudpunkter
ISO8601DateFormatter — är en specialiserad underklass av Formatter i Foundation som implementerar tvåvägskonvertering mellan Date och en sträng i ISO 8601-format. Standarden ISO 8601 (International Standard for the Representation of Dates and Times) definierar det internationella formatet för utbyte av datum och tid: 2024-07-21T14:30:00+00:00. Till skillnad från DateFormatter kräver denna klass inte att man anger dateFormat och bestämmer automatiskt strängens struktur baserat på givna alternativ.
De främsta fördelarna med ISO8601DateFormatter jämfört med DateFormatter: inget beroende av locale (tolkning fungerar likadant på alla enheter), inbyggt stöd för bråkdelar av sekunder (med valfritt antal decimaler) och automatisk bestämning av format baserat på överförda alternativ. Klassen hanterar också korrekt Z-suffixet (UTC-beteckning), tidszoner i formatet +HH:mm och reducerad precision (endast datum utan tid).
Enligt ISO Specification (ISO 8601-1:2019) stöder standarden fyra precisionsnivåer: år (2024), år-månad (2024-07), fullständigt datum (2024-07-21) och datum-tid med tidszon (2024-07-21T14:30:00+00:00). ISO8601DateFormatter täcker alla dessa nivåer genom kombinationer av formatalternativ, vilket befriar utvecklaren från att manuellt konstruera en dateFormat-sträng.
Funktionsprincip för ISO8601DateFormatter baseras på kombinationer av bitalternativ (formatOptions), där var och en aktiverar en specifik datum- eller tidkomponent i utdata. Till exempel aktiverar alternativet .withFullDate år, månad och dag; .withTime — timmar, minuter och sekunder. Genom att kombinera alternativ uppnår utvecklaren önskad precisionsnivå utan att skriva en dateFormat-sträng.
Internt använder ISO8601DateFormatter ICU-biblioteket för tolkning, men med fasta ISO 8601-regler. Detta innebär att det ignorerar Locale- och TimeZone-inställningar på enheten — resultatet är alltid förutsägbart. För inställning av tidszon används egenskapen timeZone, som som standard är lika med UTC. Om timeZone är inställt på nil, används enhetens lokala tid.
| Alternativ | Beskrivning | Exempel på utdata |
|---|---|---|
| .withFullDate | År, månad, dag | 2024-07-21 |
| .withTime | Timmar, minuter, sekunder | 14:30:00 |
| .withMilliseconds | Bråkdelar av sekunder (upp till 3 tecken) | .123 |
| .withFractionalSeconds | Bråkdelar av sekunder (valfri precision) | .123456 |
| .withTimeZone | Tidszon | +03:00 |
| .withColonSeparatorInTimeZone | Kolonseparator i tidszon | +03:00 (istället för +0300) |
| .withInternetDateTime | Fullständigt format (date + time + tz) | 2024-07-21T14:30:00+00:00 |
Kombinera alternativ: .withInternetDateTime är likvärdigt med att kombinera .withFullDate, .withTime och .withTimeZone. För tolkning av strängar med millisekunder, lägg till .withFractionalSeconds. Det är viktigt att komma ihåg att .withMilliseconds begränsar bråkdelar av sekunder till tre tecken, medan .withFractionalSeconds stöder valfri precision — från en till nio decimaler.
Formatalternativ för ISO8601DateFormatter är indelade i tre grupper: datumkomponenter (withFullDate, withYear, withMonth, withDay, withWeekOfYear), tidskomponenter (withTime, withHours, withMinutes, withSeconds) och ytterligare inställningar (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Genom att kombinera dem kan man få praktiskt taget vilket underformat av ISO 8601 som helst.
Viktig nyans: .withFractionalSeconds och .withMilliseconds är ömsesidigt uteslutande — om båda är inställda tillämpas .withFractionalSeconds. För tolkning av millisekunder från serverdata rekommenderas .withFractionalSeconds, eftersom många servrar skickar bråkdelar av sekunder med tre, sex eller nio tecken, och .withFractionalSeconds hanterar vilken längd som helst.
import Foundation
// Konfigurera ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
// Olika kombinationer av formatalternativ
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("Fullständig: \(full)")
// Tolka sträng med millisekunder
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
print("Tolkat: \(parsed)")
}
Grundläggande användning av ISO8601DateFormatter handlar om att skapa en instans, ställa in timeZone (UTC rekommenderas för serverdata) och formatOptions, varefter man kan anropa string(from:) för formatering och date(from:) för tolkning. Till skillnad från DateFormatter behöver man inte oroa sig för Locale — klassen ignorerar regionala inställningar.
import Foundation
let formatter = ISO8601DateFormatter()
// Tolka olika ISO 8601-format
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("Tolkat '\(str)': \(autoParsed)")
} else {
// Använd withFullDate för strängar med endast datum
formatter.formatOptions = [.withFullDate]
if let fallback = formatter.date(from: str) {
print("Fallback tolkat '\(str)': \(fallback)")
}
formatter.formatOptions = [.withInternetDateTime]
}
}
// Serialisera till RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")
Tolkning av datum med bråkdelar av sekunder av varierande längd — en egenskap hos många moderna API:er. Servern kan skicka både 2024-07-21T14:30:00.123Z (3 tecken) och 2024-07-21T14:30:00.123456Z (6 tecken). ISO8601DateFormatter med alternativet .withFractionalSeconds kommer att hantera båda varianterna korrekt, medan DateFormatter med dateFormat = „yyyy-MM-dd’T’HH:mm:ss.SSSZ” endast kommer att bearbeta tresiffriga millisekunder.
import Foundation
let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
.withInternetDateTime,
.withFractionalSeconds
]
// Olika precision för bråkdelar av sekunder
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)")
}
}
// Använd withMilliseconds (endast 3 siffror)
variantFormatter.formatOptions = [
.withInternetDateTime,
.withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("Med millisekunder: \(milliParsed)")
Testa tolkning av alla varianter: koden ovan visar att ISO8601DateFormatter med .withFractionalSeconds framgångsrikt bearbetar bråkdelar av sekunder av valfri längd från 1 till 9 tecken. Detta är viktigt för kompatibilitet med olika serverplattformar: .NET genererar ofta 7 tecken (100-nanosekunders tickar), Python — 6, Java — 3 eller 9 beroende på version.
DateFormatter kan också tolka ISO 8601, men kräver manuell inställning av dateFormat, locale och timeZone. Huvudproblemet är att DateFormatter är beroende av Locale, och om man inte ställer in en_US_POSIX kan tolkningen gå sönder för användare från regioner med icke-standardiserade datumformat. ISO8601DateFormatter löser detta problem på arkitekturnivå: det använder inte Locale.
| Parameter | ISO8601DateFormatter | DateFormatter |
|---|---|---|
| Locale-inställning | Krävs inte (ignorerar) | en_US_POSIX obligatoriskt |
| DateFormat | Automatisk (via alternativ) | Manuell formatsträng |
| Bråkdelar av sekunder | Valfri precision (.withFractionalSeconds) | Fast SSS |
| Z-suffix | Korrekt hantering | Via dateFormat |
| Prestanda | Högre (specialiserad) | Lägre (allmän) |
| Standard | Endast ISO 8601 | Valfritt format |
| iOS-version | iOS 10+ | iOS 2+ |
När ska DateFormatter användas: om man behöver formatera ett datum i ett icke-ISO 8601-format (till exempel „21 juli 2024” för UI) eller om stöd för iOS 9 och äldre krävs. För alla uppgifter som rör datumutbyte med servern, använd ISO8601DateFormatter — det är säkrare, mer prestandaeffektivt och kräver mindre kod. DateFormatter för ISO 8601 är en källa till potentiella buggar relaterade till locale och regionala inställningar.
Migrering från DateFormatter till ISO8601DateFormatter: ersätt skapandet av DateFormatter + inställning av dateFormat + locale + timeZone med skapandet av ISO8601DateFormatter + inställning av formatOptions + timeZone. Tolkningen av strängen förblir oförändrad via date(from:). För bakåtkompatibilitet kan man använda #available(iOS 10, *) med en fallback till DateFormatter.
Glömd formatOptions-inställning gör att formatteraren använder standardvärdet — .withInternetDateTime. Om servern endast skickar datum utan tid (2024-07-21), kommer tolkningen att returnera nil. Kontrollera alltid att formatOptions täcker alla möjliga format som kan komma från servern. För API:er med varierande format, använd fallback-försök med olika alternativkombinationer.
Förväxling mellan withMilliseconds och withFractionalSeconds — ett vanligt misstag vid tolkning av datum med bråkdelar av sekunder. withMilliseconds förväntar sig exakt 3 decimaler. Om servern skickar 6 siffror (mikrosekunder), kommer tolkning med withMilliseconds att misslyckas. Använd .withFractionalSeconds för kompatibilitet med valfritt antal tecken. .withFractionalSeconds kom i iOS 13; för äldre versioner, använd DateFormatter med dateFormat.
Ignorering av tidszon — ett annat vanligt problem. Om servern skickar datum med tidszon (+03:00) och formatteraren är inställd på UTC, kommer tolkningen inte att misslyckas, men resultatet blir i UTC. Utvecklare förväntar sig ofta att Date behåller tidszonen, men Date är ett absolut ögonblick i tiden och lagrar inte tidszoninformation. För korrekt visning, spara tidszonen separat eller använd ISO8601DateFormatter med rätt timeZone.
Enligt Apple Forum (2024) handlar cirka 20% av frågorna om ISO8601DateFormatter om formatet där sekunder är valfria. ISO 8601-standarden tillåter format utan sekunder: 2024-07-21T14:30+03:00. ISO8601DateFormatter med .withInternetDateTime stöder inte detta format — för att tolka det krävs DateFormatter med dateFormat = „yyyy-MM-dd’T’HH:mmZ”. Denna begränsning måste beaktas när man arbetar med API:er som använder förkortat tidsformat.
Vanliga frågor
ISO8601DateFormatter — specialiserad Foundation-klass för formatering och tolkning av datum i ISO 8601-format, tillgänglig från iOS 10. Bearbetar automatiskt standardformat utan manuell inställning av dateFormat.
ISO8601DateFormatter är inte beroende av Locale, använder alternativ istället för dateFormat och hanterar korrekt bråkdelar av sekunder av valfri längd. DateFormatter är universell men kräver manuell konfiguration och är känslig för buggar relaterade till regionala inställningar.
Använd alternativet .withFractionalSeconds — stöder 1 till 9 tecken efter decimalkommat. Använd inte .withMilliseconds om precisionen kan variera. .withFractionalSeconds är tillgänglig från iOS 13.
Standard är UTC. För att ändra, ställ in egenskapen timeZone. Om timeZone = nil, används enhetens lokala tid. Vid tolkning av en sträng med explicit tidszon i formatet +HH:MM tar formatteraren automatiskt hänsyn till den.
Eftersom standard formatOptions = .withInternetDateTime, som förväntar sig datum + tid + tidszon. För tolkning av endast datum, ställ in formatOptions = [.withFullDate]. För att stödja båda varianterna, använd fallback med olika alternativ.
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å