ISO8601DateFormatter: concetti chiave e formattazione ISO 8601

Autore: IT Sectr Pubblicato: 2026-07-13 Tempo di lettura: 9 min

ISO8601DateFormatter è una classe Foundation in iOS e macOS progettata per formattare e analizzare le date secondo lo standard internazionale ISO 8601. Secondo Apple Developer Documentation, 2024, ISO8601DateFormatter gestisce automaticamente i formati con millisecondi, fusi orari e frazioni di secondo senza bisogno di impostare DateFormat manualmente. A differenza di DateFormatter, questa classe non dipende da Locale e TimeZone — funziona rigorosamente secondo la specifica ISO 8601, rendendola ideale per lo scambio di date tra server e client. La classe è disponibile da iOS 10 e macOS 10.12.

Punti chiave

  • ISO8601DateFormatter — classe Foundation per formattare le date secondo lo standard ISO 8601
  • Non richiede DateFormat — il formato è determinato automaticamente dalle impostazioni delle opzioni
  • Indipendente dalla locale — funziona identicamente su tutti i dispositivi senza configurazione di Locale
  • Supporto millisecondi — gestisce frazioni di secondo di qualsiasi precisione (tre, sei o più cifre)
  • Opzioni di formattazione — withFullDate, withTime, withMilliseconds, withTimeZone e altre controllano i componenti di output

Cos'è ISO8601DateFormatter?

ISO8601DateFormatter è una sottoclasse specializzata di Formatter in Foundation che implementa la conversione bidirezionale tra Date e stringhe in formato ISO 8601. Lo standard ISO 8601 (International Standard for the Representation of Dates and Times) definisce un formato internazionale per lo scambio di date e ore: 2024-07-21T14:30:00+00:00. A differenza di DateFormatter, questa classe non richiede di specificare dateFormat e determina automaticamente la struttura della stringa in base alle opzioni fornite.

I principali vantaggi di ISO8601DateFormatter rispetto a DateFormatter: nessuna dipendenza dalla locale (l'analisi funziona identicamente su qualsiasi dispositivo), supporto integrato per le frazioni di secondo (con qualsiasi numero di decimali) e rilevamento automatico del formato basato sulle opzioni passate. La classe gestisce anche correttamente il suffisso Z (designazione UTC), i fusi orari nel formato +HH:mm e la precisione ridotta (solo data senza ora).

Secondo la Specifica ISO (ISO 8601-1:2019), lo standard supporta quattro livelli di precisione: anno (2024), anno-mese (2024-07), data completa (2024-07-21) e data-ora con fuso orario (2024-07-21T14:30:00+00:00). ISO8601DateFormatter copre tutti questi livelli attraverso una combinazione di opzioni di formato, liberando lo sviluppatore dalla costruzione manuale di stringhe dateFormat.

Come funziona ISO8601DateFormatter in Foundation?

Il principio di funzionamento di ISO8601DateFormatter si basa su una combinazione di opzioni bit (formatOptions), ciascuna delle quali include un componente specifico di data o ora nell'output. Ad esempio, l'opzione .withFullDate include anno, mese e giorno; .withTime include ore, minuti e secondi. Combinando le opzioni, lo sviluppatore ottiene il livello di precisione desiderato senza scrivere una stringa dateFormat.

Internamente, ISO8601DateFormatter utilizza la libreria ICU per l'analisi, ma con regole ISO 8601 fisse. Ciò significa che ignora le impostazioni di Locale e TimeZone sul dispositivo — il risultato è sempre prevedibile. Per impostare il fuso orario si usa la proprietà timeZone, che per impostazione predefinita è UTC. Se timeZone è impostato su nil, viene utilizzata l'ora locale del dispositivo.

OpzioneDescrizioneEsempio di output
.withFullDateAnno, mese, giorno2024-07-21
.withTimeOre, minuti, secondi14:30:00
.withMillisecondsFrazioni di secondo (fino a 3 cifre).123
.withFractionalSecondsFrazioni di secondo (qualsiasi precisione).123456
.withTimeZoneFuso orario+03:00
.withColonSeparatorInTimeZoneSeparatore due punti nel fuso orario+03:00 (contro +0300)
.withInternetDateTimeFormato completo (data + ora + fuso)2024-07-21T14:30:00+00:00

Combinazione di opzioni: .withInternetDateTime equivale a combinare .withFullDate, .withTime e .withTimeZone. Per analizzare stringhe con millisecondi, aggiungere .withFractionalSeconds. È importante ricordare che .withMilliseconds limita le frazioni di secondo a tre cifre, mentre .withFractionalSeconds supporta qualsiasi precisione — da una a nove cifre dopo il punto decimale.

Opzioni di formato ISO 8601

Le opzioni di formato di ISO8601DateFormatter sono divise in tre gruppi: componenti di data (withFullDate, withYear, withMonth, withDay, withWeekOfYear), componenti di ora (withTime, withHours, withMinutes, withSeconds) e impostazioni aggiuntive (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Combinandoli, è possibile ottenere praticamente qualsiasi sottoformato ISO 8601.

Combinazioni principali di opzioni

  • .withFullDate — solo data: 2024-07-21. Per analizzare stringhe YYYY-MM-DD
  • .withFullDate + .withTime — data e ora senza fuso orario: 2024-07-21T14:30:00
  • .withInternetDateTime — formato completo: 2024-07-21T14:30:00Z o 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — con frazioni di secondo: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — formato completo senza due punti in tz: 2024-07-21T14:30:00+0300

Sfumatura importante: .withFractionalSeconds e .withMilliseconds si escludono a vicenda — se entrambi sono impostati, viene applicato .withFractionalSeconds. Per analizzare i millisecondi dai dati del server, si raccomanda .withFractionalSeconds, poiché molti server inviano frazioni di secondo con tre, sei o nove cifre e .withFractionalSeconds gestisce qualsiasi lunghezza.

swift
import Foundation

// Configure ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// Different format option combinations
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Date: \(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("Full: \(full)")

// Parse string with milliseconds
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("Parsed: \(parsed)")
}

ISO8601DateFormatter in Swift: esempi di codice

Uso di base di ISO8601DateFormatter si riduce alla creazione di un'istanza, all'impostazione di timeZone (UTC è consigliato per i dati del server) e formatOptions, dopodiché è possibile chiamare string(from:) per formattare e date(from:) per analizzare. A differenza di DateFormatter, non c'è bisogno di preoccuparsi di Locale — la classe ignora le impostazioni regionali.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// Parse different ISO 8601 formats
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("Parsed '\(str)': \(autoParsed)")
    } else {
        // Use withFullDate for date-only strings
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("Fallback parsed '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// Serialize to RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

Analizzare date con frazioni di secondo di lunghezza variabile è una caratteristica di molte API moderne. Un server può inviare 2024-07-21T14:30:00.123Z (3 cifre) o 2024-07-21T14:30:00.123456Z (6 cifre). ISO8601DateFormatter con l'opzione .withFractionalSeconds gestirà correttamente entrambe le varianti, mentre DateFormatter con dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" gestirà solo millisecondi a tre cifre.

swift
import Foundation

let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withFractionalSeconds
]

// Different fractional second precision
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)")
    }
}

// Use withMilliseconds (3 digits only)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("With milliseconds: \(milliParsed)")

Test di analisi di tutte le varianti: il codice mostrato dimostra che ISO8601DateFormatter con .withFractionalSeconds gestisce con successo frazioni di secondo di qualsiasi lunghezza da 1 a 9 cifre. Questo è importante per la compatibilità con diverse piattaforme server: .NET genera spesso 7 cifre (tick da 100 nanosecondi), Python — 6, Java — 3 o 9 a seconda della versione.

Confronto con DateFormatter per ISO 8601

DateFormatter può anch'esso analizzare ISO 8601, ma richiede la configurazione manuale di dateFormat, locale e timeZone. Il problema principale è che DateFormatter dipende da Locale, e se non si imposta en_US_POSIX, l'analisi potrebbe fallire per gli utenti di regioni con formati di data non standard. ISO8601DateFormatter risolve questo problema a livello architetturale: non utilizza Locale.

ParametroISO8601DateFormatterDateFormatter
Configurazione LocaleNon richiesta (ignora)en_US_POSIX obbligatorio
DateFormatAutomatico (tramite opzioni)Stringa di formato manuale
Frazioni di secondoQualsiasi precisione (.withFractionalSeconds)SSS fisso
Suffisso ZGestito correttamenteTramite dateFormat
PrestazioniSuperiori (specializzato)Inferiori (generico)
StandardSolo ISO 8601Qualsiasi formato
Versione iOSiOS 10+iOS 2+

Quando usare DateFormatter: se è necessario formattare una data in un formato non ISO 8601 (ad esempio, "21 luglio 2024" per l'interfaccia utente) o se è necessario supportare iOS 9 e versioni precedenti. Per tutte le attività di scambio di date tra server e client, utilizzare ISO8601DateFormatter — è più sicuro, più performante e richiede meno codice. DateFormatter per ISO 8601 è una fonte di potenziali bug legati alla locale e alle impostazioni regionali.

Migrazione da DateFormatter a ISO8601DateFormatter: sostituire la creazione di DateFormatter + configurazione di dateFormat + locale + timeZone con la creazione di ISO8601DateFormatter + configurazione di formatOptions + timeZone. L'analisi della stringa rimane invariata tramite date(from:). Per la retrocompatibilità, è possibile utilizzare #available(iOS 10, *) con un fallback a DateFormatter.

Errori comuni nell'analisi ISO 8601

Configurazione dimenticata di formatOptions fa sì che il formattatore utilizzi il valore predefinito — .withInternetDateTime. Se il server invia una data senza ora (2024-07-21), l'analisi restituirà nil. Verificare sempre che formatOptions copra tutti i formati possibili che possono arrivare dal server. Per le API con formati variabili, utilizzare tentativi di fallback con diverse combinazioni di opzioni.

Confusione tra withMilliseconds e withFractionalSeconds è un errore comune nell'analisi di date con frazioni di secondo. withMilliseconds si aspetta esattamente 3 cifre dopo il punto decimale. Se il server invia 6 cifre (microsecondi), l'analisi con withMilliseconds fallirà. Utilizzare .withFractionalSeconds per la compatibilità con qualsiasi numero di cifre. .withFractionalSeconds è disponibile da iOS 13; per le versioni precedenti, utilizzare DateFormatter con dateFormat.

Ignorare il fuso orario è un altro problema comune. Se il server invia una data con fuso orario (+03:00) e il formattatore è impostato su UTC, l'analisi non fallirà, ma il risultato sarà in UTC. Gli sviluppatori spesso si aspettano che Date conservi il fuso orario, ma Date è un momento assoluto nel tempo — non memorizza informazioni sul fuso orario. Per una visualizzazione corretta, salvare il fuso orario separatamente o utilizzare ISO8601DateFormatter con il timeZone appropriato.

Secondo l'Apple Forum (2024), circa il 20% delle domande su ISO8601DateFormatter riguarda il formato in cui i secondi sono opzionali. Lo standard ISO 8601 consente un formato senza secondi: 2024-07-21T14:30+03:00. ISO8601DateFormatter con .withInternetDateTime non supporta questo formato — per analizzarlo sarà necessario DateFormatter con dateFormat = "yyyy-MM-dd'T'HH:mmZ". Questa limitazione è importante da considerare quando si lavora con API che utilizzano il formato orario abbreviato.

Domande frequenti

Cos'è ISO8601DateFormatter?

ISO8601DateFormatter è una classe Foundation specializzata per formattare e analizzare date in formato ISO 8601, disponibile da iOS 10. Gestisce automaticamente i formati standard senza impostare manualmente dateFormat.

In cosa si differenzia ISO8601DateFormatter da DateFormatter?

ISO8601DateFormatter non dipende da Locale, usa opzioni invece di dateFormat e gestisce correttamente frazioni di secondo di qualsiasi lunghezza. DateFormatter è universale, ma richiede configurazione manuale ed è soggetto a bug legati alle impostazioni regionali.

Come gestire frazioni di secondo di lunghezza variabile?

Utilizzare l'opzione .withFractionalSeconds — supporta da 1 a 9 cifre dopo il punto decimale. Non utilizzare .withMilliseconds se la precisione può variare. .withFractionalSeconds è disponibile da iOS 13.

Quale fuso orario usa ISO8601DateFormatter?

UTC per impostazione predefinita. Per cambiarlo, impostare la proprietà timeZone. Se timeZone = nil, viene utilizzata l'ora locale del dispositivo. Quando si analizza una stringa con fuso orario esplicito nel formato +HH:MM, il formattatore lo considera automaticamente.

Perché l'analisi di una data senza ora restituisce nil?

Perché formatOptions per impostazione predefinita è .withInternetDateTime, che si aspetta data + ora + fuso orario. Per analizzare solo la data, impostare formatOptions = [.withFullDate]. Per supportare entrambi i formati, utilizzare il fallback con diverse opzioni.

Riepilogo

  • ISO8601DateFormatter — classe specializzata per ISO 8601, più sicura e semplice di DateFormatter
  • Opzioni di formato sostituiscono dateFormat manuale — combinare .withFullDate, .withTime, .withTimeZone
  • Indipendente da Locale — l'analisi funziona identicamente su tutti i dispositivi senza configurare la locale
  • .withFractionalSeconds gestisce frazioni di secondo di qualsiasi precisione (1–9 cifre)
  • DateFormatter è inferiore in prestazioni, sicurezza e semplicità per le attività ISO 8601
  • Confusione di opzioni — withMilliseconds e withFractionalSeconds non sono intercambiabili
  • Formato senza secondi (2024-07-21T14:30+03:00) non supportato — necessario DateFormatter

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche