DateFormatter: Conceitos-chave, formatação de data e localização

Autor: IT Sectr Publicado: 2026-07-12 Tempo de leitura: 7 min

DateFormatter é uma classe Foundation projetada para conversão bidirecional entre objetos Date e suas representações em string. A classe leva em conta a localidade, o fuso horário e o calendário do usuário, garantindo a exibição correta de datas em qualquer região do mundo. De acordo com a Documentação para Desenvolvedores Apple (2025), o DateFormatter suporta quatro estilos predefinidos de data e hora, bem como formatos totalmente personalizados através de uma string de modelo. Sem o DateFormatter é impossível exibir corretamente uma data para o usuário em uma aplicação internacionalizada.

Principais conclusões

  • DateFormatter — uma classe para converter Date em string e vice-versa com suporte a localidade e fuso horário.
  • dateStyle e timeStyle — estilos predefinidos (.short, .medium, .long, .full) para formatação rápida.
  • dateFormat — uma string de modelo para formato personalizado especificada através de símbolos Unicode LDML.
  • Locale e TimeZone — propriedades do formatador que determinam a exibição regional e o fuso horário.
  • ISO8601DateFormatter — uma alternativa mais rápida para o formato ISO 8601 ao serializar em API.

O que é DateFormatter?

DateFormatter é uma classe do framework Foundation que implementa a conversão bidirecional entre Date e string. Apareceu pela primeira vez no OpenStep como NSDateFormatter e desde então permaneceu a principal ferramenta para formatação de datas em todas as plataformas Apple. A classe herda de Formatter e fornece uma API conveniente para exibição localizada de datas.

O DateFormatter funciona com base em padrões Unicode LDML — os mesmos usados no ICU (International Components for Unicode). O padrão é definido através da propriedade dateFormat, onde os símbolos y, M, d, H, m, s correspondem a ano, mês, dia, horas, minutos, segundos. A repetição de um símbolo determina o formato: "y" — ano de dois dígitos, "yyyy" — ano de quatro dígitos.

Criar um DateFormatter é uma operação cara, pois durante a inicialização os dados de localidade e calendário são carregados. A Apple recomenda criar um formatador uma vez para cada tipo de formatação e reutilizá-lo. No SwiftUI e UIKit, os formatadores são frequentemente armazenados em cache em propriedades estáticas ou criados lentamente no primeiro acesso.

DateFormatter no iOS SDK

DateFormatter é usado em muitos componentes do sistema iOS. O UIDatePicker usa DateFormatter internamente para exibir datas no modo countDownTimer. Um TextField com um formatador pode validar automaticamente as datas inseridas pelo usuário. O Core Data suporta atributos do tipo Date, mas sua representação em string é sempre tratada através do DateFormatter.

Segurança em threads — DateFormatter não é seguro para threads. Modificar as propriedades do formatador de diferentes threads leva a comportamento indefinido. Para uso multi-thread, crie instâncias separadas do formatador para cada thread ou use sincronização através de NSLock ou uma fila serial.

Estilos de formatação do DateFormatter

dateStyle e timeStyle são as formas mais simples de configurar a exibição de datas. Cada estilo tem quatro variantes: .short, .medium, .long, .full. A combinação de dateStyle e timeStyle permite configurar independentemente o formato de data e hora, e a propriedade .none desativa a parte correspondente.

Para a localidade dos EUA, .short formata a data como "7/21/26", e para a russa como "21.07.2026". O estilo .long para a localidade russa exibe "21 de julho de 2026", e .full — "terça-feira, 21 de julho de 2026" com o dia da semana. Todos os quatro estilos se adaptam automaticamente aos padrões regionais, incluindo a ordem dos componentes e separadores.

SFDateFormatter no iOS 15+ fornece uma abordagem alternativa através do RelativeDateFormatter e DateIntervalFormatter. O RelativeDateFormatter exibe "hoje", "ontem", "em 3 dias" para contexto imediato. O DateIntervalFormatter exibe intervalos de datas: "21–25 de julho de 2026" — para reservas e planejamento.

EstiloExemplo (ru_RU)Exemplo (en_US)
.short21.07.20267/21/26
.medium21 jul 2026Jul 21, 2026
.long21 de julho de 2026July 21, 2026
.fullterça-feira, 21 de julho de 2026Tuesday, July 21, 2026

Ao combinar estilos, o DateFormatter seleciona automaticamente o separador: para .short.date + .short.time o resultado pode ser "21.07.2026, 14:30". Para .full.date + .full.time — "terça-feira, 21 de julho de 2026, 14:30:00 MSK". O separador é gerenciado pela localidade, não pelo desenvolvedor — isso garante a conformidade com as expectativas regionais do usuário.

Formatos personalizados via dateFormat

dateFormat permite definir um padrão de formatação arbitrário usando símbolos de especificação Unicode LDML. Isso dá controle total sobre a exibição: você pode mostrar apenas o ano e mês, ou o dia da semana sem a data, ou a hora sem segundos. O formato personalizado é indispensável para requisitos de design específicos.

Símbolos principais — yyyy (ano: 2026), MM (mês: 07), dd (dia: 21), HH (horas: 14), mm (minutos: 30), ss (segundos: 00). Para o nome completo do mês use MMMM (julho), para abreviado — MMM (jul). Dia da semana — EEEE (terça-feira), abreviado — E (ter).

Ao usar dateFormat é importante definir a localidade do formatador. Se a localidade não for definida, o formatador usa a localidade do sistema, o que pode ser indesejável para um formato fixo em uma API. A Apple recomenda definir locale = Locale(identifier: "en_US_POSIX") para um formato fixo entre regiões, especialmente ao analisar datas de respostas do servidor.

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

// Analisando uma string personalizada
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!

Um erro no dateFormat é uma das causas comuns de falhas do aplicativo. Se o formato não corresponder à string, o método date(from:) retorna nil. Use guard let ou ?? para desembrulho seguro de opcionais. Para validar o formato, teste-o em todos os idiomas suportados — alguns símbolos LDML funcionam de maneira diferente em diferentes localidades.

Localização e TimeZone

Locale determina como os nomes dos meses, dias da semana e separadores são exibidos. O DateFormatter usa Locale.current por padrão, mas em alguns cenários é necessário especificar uma localidade específica: para um formato fixo em logs use en_US_POSIX, para datas do servidor — a localidade que corresponde ao servidor.

A propriedade TimeZone determina o fuso horário para exibição. Por padrão, o fuso horário do sistema é usado, mas para aplicações com público internacional, muitas vezes é necessário exibir datas no fuso horário do usuário ou em UTC. Alterar o timeZone afeta apenas a exibição — o valor Date permanece inalterado.

Uma característica importante: se DateFormatter for usado para analisar uma string e a string contiver uma indicação de fuso horário (por exemplo, "2026-07-21T14:30:00Z" com Z para UTC), a propriedade timeZone é ignorada — o formatador usa o fuso horário da string. Se o fuso horário estiver ausente na string, o timeZone do formatador é aplicado.

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"

// Analisando sem fuso horário na string
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!

AutoupdatingCurrentLocale — um tipo especial de localidade que é atualizada automaticamente quando as configurações do sistema do usuário mudam. O DateFormatter a suporta por padrão. Se o aplicativo estiver rodando em segundo plano e o usuário mudar o idioma do sistema, um formatador criado antes da mudança continuará usando a localidade antiga — para atualizar é necessário criar uma nova instância.

ISO8601DateFormatter e alternativas

ISO8601DateFormatter é um formatador especializado para trabalhar com datas no formato ISO 8601. Este formato é o padrão de fato para APIs REST, JSON e troca de dados. O ISO8601DateFormatter funciona significativamente mais rápido que o DateFormatter porque não depende de localidade e usa uma gramática de análise fixa.

Opções principais do formatador — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (adiciona milissegundos), .withTimeZone (inclui o offset do fuso horário). Combinando opções, você pode obter qualquer variante ISO 8601: com milissegundos, com fuso horário, apenas com data.

JSONEncoder.DateEncodingStrategy permite configurar globalmente a codificação de datas para todos os modelos Codable. Opções — .iso8601 (usa ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. A escolha da estratégia afeta todo o ciclo de vida da serialização e deve ser consistente em todos os endpoints da API.

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

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

// Alternativa: JSONEncoder com formatador personalizado
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)

DateFormatter vs ISO8601DateFormatter — escolha ISO8601DateFormatter para serializar e analisar datas em API, pois é 5-10 vezes mais rápido que o DateFormatter e não está sujeito a erros de localização. Use DateFormatter para a interface do usuário onde é necessária exibição localizada com nomes de meses e dias no idioma nativo do usuário.

Exemplos de formatação de datas

Vamos ver cenários reais de uso do DateFormatter em um aplicativo iOS: exibição em um feed de notícias, inserção de data de nascimento e exportação de um relatório com datas em diferentes fusos horários.

Exibindo data de notícia em uma lista

RelativeDateFormatter é ideal para feeds de notícias. Ele exibe "agora mesmo", "há 5 minutos", "ontem" para notícias recentes e muda para a data completa para as antigas. O limite de mudança é configurado através do calendar: para notícias use um limite de 24 horas, para mensageiros — uma semana.

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

Inserção de data de nascimento — outro cenário comum. O DateFormatter é configurado com um dateFormat específico "dd.MM.yyyy" e locale "ru_RU". Ao analisar a string inserida, é importante tratar possíveis erros: o formatador retorna nil para uma string inválida. Após a análise bem-sucedida, a data é verificada para estar dentro de um intervalo aceitável — não antes de 1900, não depois de hoje.

Exportação de relatório com datas requer um formato fixo independente da localidade do usuário. Use dateFormat "yyyy-MM-dd HH:mm:ss" com locale en_US_POSIX e fuso horário UTC. Esta abordagem garante que o arquivo será aberto corretamente em qualquer país, independentemente das configurações regionais do sistema.

CenárioFormatadorConfiguração chave
Feed de notíciasRelativeDateFormatterunitsStyle = .full
Inserção de dataDateFormatterdateFormat + fallback
Serialização APIISO8601DateFormatterwithInternetDateTime
Exportação de relatórioDateFormatteren_US_POSIX + UTC

Perguntas frequentes

Por que DateFormatter retorna nil para uma string válida?

A razão mais comum — uma incompatibilidade entre dateFormat e o formato da string. Por exemplo, o formato "dd.MM.yyyy" não analisará a string "2026-07-21". A segunda razão — incompatibilidade de localidade: a string "July 21, 2026" não será analisada com a localidade ru_RU. A terceira — erros de digitação nos símbolos LDML: use yyyy, não YYYY (significado diferente).

Devo criar um novo DateFormatter para cada chamada?

Não. DateFormatter é um objeto pesado, sua inicialização inclui o carregamento de dados de localidade. Crie uma instância por tipo de formatação e reutilize-a. Em um ambiente multi-thread, use armazenamento local de thread ou um pool de formatadores com uma fila serial para sincronização.

Qual a diferença entre DateFormatter e RelativeDateFormatter?

DateFormatter exibe uma data absoluta (21 de julho de 2026), enquanto RelativeDateFormatter exibe uma data relativa (hoje, ontem, em 3 dias). O RelativeDateFormatter foi introduzido no iOS 15+ e usa o mesmo modelo LDML, mas seleciona automaticamente a exibição relativa.

Como lidar com datas sem fuso horário da API?

Defina o timeZone do formatador para UTC antes de analisar. Se o servidor retornar uma data em horário local sem indicação de fuso horário, verifique a especificação da API — muito provavelmente o UTC está implícito. Para ISO 8601 com Z no final, timeZone não é necessário — o formatador analisa o offset da string.

Como tornar o DateFormatter seguro para threads?

Não use uma única instância de diferentes threads sem sincronização. Crie uma nova instância em cada thread ou use Thread.current.threadDictionary para armazenamento. Uma alternativa é o NSLock com bloqueio durante a duração de string(from:) e date(from:).

Resumo

  • DateFormatter — uma classe Foundation para converter Date em string e vice-versa com suporte a localidade, fuso horário e calendário.
  • Estilos predefinidos dateStyle e timeStyle com variantes .short, .medium, .long, .full cobrem a maioria dos cenários de UI.
  • dateFormat personalizado através de símbolos LDML dá controle total sobre o formato, mas requer cuidado com a localização.
  • Locale e TimeZone — propriedades necessárias para exibição correta: para UI — localidade do sistema, para API — en_US_POSIX e UTC.
  • ISO8601DateFormatter — a escolha preferida para serialização de datas em API devido à velocidade e estabilidade.
  • DateFormatter não é seguro para threads — use instâncias separadas para cada thread ou sincronize o acesso.
  • RelativeDateFormatter (iOS 15+) — a solução ideal para exibir datas relativas em feeds de notícias e mensageiros.

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