ISO8601DateFormatter: conceitos-chave e formatação ISO 8601

Autor: IT Sectr Publicado: 2026-07-13 Tempo de leitura: 9 min

ISO8601DateFormatter é uma classe Foundation no iOS e macOS projetada para formatar e analisar datas no padrão internacional ISO 8601. De acordo com Apple Developer Documentation, 2024, ISO8601DateFormatter lida automaticamente com formatos com milissegundos, fusos horários e frações de segundo sem precisar definir DateFormat manualmente. Ao contrário do DateFormatter, esta classe não depende de Locale e TimeZone — funciona estritamente de acordo com a especificação ISO 8601, tornando-a ideal para troca de datas entre servidor e cliente. A classe está disponível desde iOS 10 e macOS 10.12.

Principais Pontos

  • ISO8601DateFormatter — classe Foundation para formatar datas conforme o padrão ISO 8601
  • Não requer DateFormat — o formato é determinado automaticamente pelas configurações de opções
  • Independente de localidade — funciona igualmente em todos os dispositivos sem configurar Locale
  • Suporte a milissegundos — lida com frações de segundo de qualquer precisão (três, seis ou mais dígitos)
  • Opções de formatação — withFullDate, withTime, withMilliseconds, withTimeZone e outras controlam os componentes de saída

O que é ISO8601DateFormatter?

ISO8601DateFormatter é uma subclasse especializada de Formatter no Foundation que implementa a conversão bidirecional entre Date e strings no formato ISO 8601. O padrão ISO 8601 (International Standard for the Representation of Dates and Times) define um formato internacional para troca de datas e horas: 2024-07-21T14:30:00+00:00. Ao contrário do DateFormatter, esta classe não requer especificação de dateFormat e determina automaticamente a estrutura da string com base nas opções fornecidas.

As principais vantagens do ISO8601DateFormatter sobre o DateFormatter: ausência de dependência de localidade (a análise funciona igualmente em qualquer dispositivo), suporte integrado para frações de segundo (com qualquer número de casas decimais) e deteção automática de formato com base nas opções passadas. A classe também lida corretamente com o sufixo Z (designação UTC), fusos horários no formato +HH:mm e precisão reduzida (apenas data sem hora).

De acordo com a Especificação ISO (ISO 8601-1:2019), o padrão suporta quatro níveis de precisão: ano (2024), ano-mês (2024-07), data completa (2024-07-21) e data-hora com fuso horário (2024-07-21T14:30:00+00:00). O ISO8601DateFormatter cobre todos esses níveis através de uma combinação de opções de formato, libertando o desenvolvedor da construção manual de strings dateFormat.

Como o ISO8601DateFormatter funciona no Foundation?

O princípio de funcionamento do ISO8601DateFormatter é baseado numa combinação de opções de bits (formatOptions), cada uma incluindo um componente específico de data ou hora na saída. Por exemplo, a opção .withFullDate inclui ano, mês e dia; .withTime inclui horas, minutos e segundos. Combinando opções, o desenvolvedor obtém o nível de precisão desejado sem escrever uma string dateFormat.

Internamente, o ISO8601DateFormatter utiliza a biblioteca ICU para análise, mas com regras fixas ISO 8601. Isto significa que ignora as configurações de Locale e TimeZone do dispositivo — o resultado é sempre previsível. Para definir o fuso horário, utiliza-se a propriedade timeZone, cujo valor padrão é UTC. Se timeZone for definido como nil, é utilizada a hora local do dispositivo.

OpçãoDescriçãoExemplo de saída
.withFullDateAno, mês, dia2024-07-21
.withTimeHoras, minutos, segundos14:30:00
.withMillisecondsFrações de segundo (até 3 dígitos).123
.withFractionalSecondsFrações de segundo (qualquer precisão).123456
.withTimeZoneFuso horário+03:00
.withColonSeparatorInTimeZoneSeparador de dois pontos no fuso horário+03:00 (vs +0300)
.withInternetDateTimeFormato completo (data + hora + tz)2024-07-21T14:30:00+00:00

Combinação de opções: .withInternetDateTime é equivalente a combinar .withFullDate, .withTime e .withTimeZone. Para analisar strings com milissegundos, adicione .withFractionalSeconds. É importante lembrar que .withMilliseconds limita as frações de segundo a três dígitos, enquanto .withFractionalSeconds suporta qualquer precisão — de um a nove dígitos após o ponto decimal.

Opções de formato ISO 8601

As opções de formato do ISO8601DateFormatter dividem-se em três grupos: componentes de data (withFullDate, withYear, withMonth, withDay, withWeekOfYear), componentes de hora (withTime, withHours, withMinutes, withSeconds) e configurações adicionais (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Combinando-os, pode obter praticamente qualquer subformato ISO 8601.

Combinações principais de opções

  • .withFullDate — apenas data: 2024-07-21. Para analisar strings YYYY-MM-DD
  • .withFullDate + .withTime — data e hora sem fuso horário: 2024-07-21T14:30:00
  • .withInternetDateTime — formato completo: 2024-07-21T14:30:00Z ou 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — com frações de segundo: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — formato completo sem dois pontos em tz: 2024-07-21T14:30:00+0300

Nuance importante: .withFractionalSeconds e .withMilliseconds são mutuamente exclusivos — se ambos forem definidos, .withFractionalSeconds prevalece. Para analisar milissegundos de dados do servidor, recomenda-se .withFractionalSeconds, pois muitos servidores enviam frações de segundo com três, seis ou nove dígitos, e .withFractionalSeconds lida com qualquer comprimento.

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 em Swift: exemplos de código

Uso básico do ISO8601DateFormatter resume-se a criar uma instância, configurar timeZone (recomenda-se UTC para dados do servidor) e formatOptions, após o que pode chamar string(from:) para formatar e date(from:) para analisar. Ao contrário do DateFormatter, não precisa se preocupar com Locale — a classe ignora as configurações regionais.

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

Analisar datas com frações de segundo de comprimento variável é uma característica de muitas APIs modernas. Um servidor pode enviar 2024-07-21T14:30:00.123Z (3 dígitos) ou 2024-07-21T14:30:00.123456Z (6 dígitos). O ISO8601DateFormatter com a opção .withFractionalSeconds lidará corretamente com ambos, enquanto o DateFormatter com dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" apenas lidará com milissegundos de três dígitos.

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

Teste de análise de todas as variantes: o código mostrado demonstra que o ISO8601DateFormatter com .withFractionalSeconds lida com sucesso com frações de segundo de qualquer comprimento, de 1 a 9 dígitos. Isto é importante para compatibilidade com diferentes plataformas de servidor: .NET gera frequentemente 7 dígitos (ticks de 100 nanossegundos), Python — 6, Java — 3 ou 9 dependendo da versão.

Comparação com DateFormatter para ISO 8601

DateFormatter também pode analisar ISO 8601, mas requer configuração manual de dateFormat, locale e timeZone. O principal problema é que o DateFormatter depende de Locale, e se não definir en_US_POSIX, a análise pode falhar para utilizadores de regiões com formatos de data não padrão. O ISO8601DateFormatter resolve este problema ao nível da arquitetura: não utiliza Locale.

ParâmetroISO8601DateFormatterDateFormatter
Configuração de LocaleNão requerida (ignora)en_US_POSIX obrigatório
DateFormatAutomático (através de opções)String de formato manual
Frações de segundoQualquer precisão (.withFractionalSeconds)SSS fixo
Sufixo ZLida corretamenteAtravés de dateFormat
DesempenhoMaior (especializado)Menor (geral)
PadrãoApenas ISO 8601Qualquer formato
Versão iOSiOS 10+iOS 2+

Quando usar DateFormatter: se precisar de formatar uma data num formato não ISO 8601 (por exemplo, "21 de julho de 2024" para a UI) ou se precisar de suportar iOS 9 e versões anteriores. Para todas as tarefas de troca de datas entre servidor e cliente, use ISO8601DateFormatter — é mais seguro, mais eficiente e requer menos código. DateFormatter para ISO 8601 é uma fonte de potenciais erros relacionados com a localidade e configurações regionais.

Migração de DateFormatter para ISO8601DateFormatter: substitua a criação de DateFormatter + configuração de dateFormat + locale + timeZone pela criação de ISO8601DateFormatter + configuração de formatOptions + timeZone. A análise da string permanece inalterada através de date(from:). Para compatibilidade reversa, pode usar #available(iOS 10, *) com um fallback para DateFormatter.

Erros comuns ao analisar ISO 8601

Configuração esquecida de formatOptions faz com que o formatador use o valor padrão — .withInternetDateTime. Se o servidor enviar uma data sem hora (2024-07-21), a análise retornará nil. Verifique sempre se formatOptions cobre todos os formatos possíveis que podem vir do servidor. Para APIs com formatos variáveis, use tentativas de fallback com diferentes combinações de opções.

Confusão entre withMilliseconds e withFractionalSeconds é um erro comum ao analisar datas com frações de segundo. withMilliseconds espera exatamente 3 dígitos após o ponto decimal. Se o servidor enviar 6 dígitos (microssegundos), a análise com withMilliseconds falhará. Use .withFractionalSeconds para compatibilidade com qualquer número de dígitos. .withFractionalSeconds está disponível desde iOS 13; para versões mais antigas, use DateFormatter com dateFormat.

Ignorar o fuso horário é outro problema comum. Se o servidor enviar uma data com fuso horário (+03:00) e o formatador estiver configurado para UTC, a análise não falhará, mas o resultado estará em UTC. Os desenvolvedores frequentemente esperam que Date preserve o fuso horário, mas Date é um momento absoluto no tempo — não armazena informações de fuso horário. Para exibição correta, guarde o fuso horário separadamente ou use ISO8601DateFormatter com o timeZone adequado.

De acordo com o Apple Forum (2024), cerca de 20% das perguntas sobre ISO8601DateFormatter estão relacionadas ao formato onde os segundos são opcionais. O padrão ISO 8601 permite um formato sem segundos: 2024-07-21T14:30+03:00. O ISO8601DateFormatter com .withInternetDateTime não suporta este formato — para analisá-lo será necessário DateFormatter com dateFormat = "yyyy-MM-dd'T'HH:mmZ". Esta limitação é importante considerar ao trabalhar com APIs que utilizam o formato de hora abreviado.

Perguntas Frequentes

O que é ISO8601DateFormatter?

ISO8601DateFormatter é uma classe especializada Foundation para formatar e analisar datas no formato ISO 8601, disponível desde iOS 10. Lida automaticamente com formatos padrão sem definir dateFormat manualmente.

Como o ISO8601DateFormatter difere do DateFormatter?

ISO8601DateFormatter não depende de Locale, usa opções em vez de dateFormat e lida corretamente com frações de segundo de qualquer comprimento. DateFormatter é universal, mas requer configuração manual e é propenso a erros relacionados com configurações regionais.

Como lidar com frações de segundo de comprimento variável?

Use a opção .withFractionalSeconds — suporta de 1 a 9 dígitos após o ponto decimal. Não use .withMilliseconds se a precisão puder variar. .withFractionalSeconds está disponível desde iOS 13.

Qual fuso horário o ISO8601DateFormatter usa?

UTC por padrão. Para alterar, defina a propriedade timeZone. Se timeZone = nil, é usada a hora local do dispositivo. Ao analisar uma string com fuso horário explícito no formato +HH:MM, o formatador considera-o automaticamente.

Por que analisar uma data sem hora retorna nil?

Porque formatOptions por defeito é .withInternetDateTime, que espera data + hora + fuso horário. Para analisar apenas a data, defina formatOptions = [.withFullDate]. Para suportar ambos os formatos, use fallback com diferentes opções.

Resumo

  • ISO8601DateFormatter — classe especializada para ISO 8601, mais segura e simples que DateFormatter
  • Opções de formato substituem dateFormat manual — combine .withFullDate, .withTime, .withTimeZone
  • Independente de Locale — análise funciona igualmente em todos os dispositivos sem configurar locale
  • .withFractionalSeconds lida com frações de segundo de qualquer precisão (1–9 dígitos)
  • DateFormatter é inferior em desempenho, segurança e simplicidade para tarefas ISO 8601
  • Confusão de opções — withMilliseconds e withFractionalSeconds não são intercambiáveis
  • Formato sem segundos (2024-07-21T14:30+03:00) não é suportado — DateFormatter necessário

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também