DateComponents é uma estrutura do Foundation que armazena componentes de data calendárica como campos separados: ano, mês, dia, hora, minuto, segundo e outros. Ao contrário de Date, que representa um momento absoluto no tempo, DateComponents contém valores legíveis por humanos que dependem do calendário e do fuso horário. De acordo com a Documentação do Apple Developer (2025), DateComponents é usado como um elo intermediário entre Date e Calendar — através dela, datas calendárias são extraídas e construídas, cálculos e deslocamentos de data são realizados sem aritmética manual.
Principais pontos
DateComponents é um tipo de valor do Foundation projetado para armazenar componentes de tempo calendário. Cada componente é representado por um campo Int opcional: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear e outros.
A principal diferença do Date é a vinculação ao calendário. Date armazena tempo absoluto (número de segundos desde a data de referência), enquanto DateComponents é uma representação legível que só faz sentido no contexto de um Calendar específico. O mesmo Date pode ser representado por diferentes DateComponents em diferentes calendários e fusos horários.
DateComponents não é um tipo de tempo independente, mas sim um contêiner de dados. Para interpretar DateComponents como uma data, é necessário um Calendar que entenda como os componentes se relacionam com o sistema calendário. Calendar.dateComponents(from: Date) realiza a extração de componentes, Calendar.date(from: DateComponents) realiza a montagem reversa.
Cada campo de DateComponents é opcional (Int?), o que é fundamental para trabalhar com datas parciais. Se apenas ano e mês forem especificados, Calendar preenche os campos ausentes com valores padrão: dia = 1, hora = 0, minuto = 0. Isso é conveniente para criar datas de início de período — você só precisa especificar os componentes relevantes.
Ao comparar DateComponents com o operador ==, apenas os campos especificados (não nil) são comparados. Duas estruturas DateComponents ambas com ano 2026, mas meses diferentes, são consideradas distintas. isEqual do NSObjectProtocol não se aplica a DateComponents — DateComponents não herda de NSObject.
Campos principais de DateComponents incluem year, month, day, hour, minute, second, nanosecond. Cada campo armazena um valor numérico na unidade correspondente: ano — 2026, mês — 1..12, dia — 1..31, hora — 0..23, minuto — 0..59, segundo — 0..59. Nanossegundos podem variar de 0 a 999999999.
Campos de semana — weekday (1..7, onde 1 = domingo no calendário gregoriano), weekOfMonth, weekOfYear. Esses campos dependem do Calendar e não têm significado fora do seu contexto. weekday depende da configuração firstWeekday do calendário: na localidade russa a semana começa na segunda-feira (weekday = 2 no sistema gregoriano), enquanto na americana começa no domingo (weekday = 1).
Campos especializados — quarter (1..4), yearForWeekOfYear (o ano ao qual a semana pertence), isLeapMonth (um sinalizador booleano para meses bissextos nos calendários hebraico ou chinês). Os campos calendar e timeZone armazenam referências aos objetos correspondentes com os quais a estrutura foi criada.
| Categoria | Campos | Intervalo |
|---|---|---|
| Calendário | year, month, day | 1..∞, 1..12, 1..31 |
| Tempo | hour, minute, second, nanosecond | 0..23, 0..59, 0..59, 0..999999999 |
| Semana | weekday, weekOfMonth, weekOfYear | 1..7, 1..5, 1..53 |
| Especiais | quarter, yearForWeekOfYear | 1..4, dependente |
Ao extrair componentes via Calendar.dateComponents, é importante solicitar apenas os campos necessários para desempenho. Calendar extrai todos os campos solicitados em uma única passada — isso é significativamente mais rápido do que chamar Calendar.component para cada campo individualmente.
Inicializar DateComponents — a maneira mais simples: crie uma estrutura vazia e preencha os campos necessários. Todos os campos não especificados recebem automaticamente nil. Uma data criada a partir de componentes parciais não é validada na inicialização — um erro só pode ocorrer ao converter para Date via Calendar.
O inicializador DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) permite definir todos os campos em uma única chamada. Este inicializador é conveniente para criar uma data completa a partir de valores prontos, mas raramente é usado com mais de 5-6 argumentos devido à legibilidade.
Calendar.dateComponents(_:from:) — a forma principal de obter DateComponents a partir de um Date existente. O segundo argumento é o conjunto de componentes a extrair. Calendar realiza os cálculos calendários considerando o fuso horário e retorna uma estrutura apenas com os campos solicitados; os campos restantes permanecem nil.
import Foundation
// Criação via inicializador de campos
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21
// Extração de Date
let now = Date()
let extracted = Calendar.current.dateComponents(
[.year, .month, .day],
from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")
// Criação via inicializador estendido
let birthday = DateComponents(
calendar: Calendar.current,
year: 1990, month: 5, day: 15
)
Ao criar DateComponents definindo os campos manualmente, sempre verifique o Calendar antes de converter para Date. Ao converter date(from:), Calendar pode retornar nil se os componentes formarem uma data inexistente — por exemplo, 31 de fevereiro ou 30 de fevereiro em um ano não bissexto. A validação da data é responsabilidade do Calendar, não do DateComponents.
Calendar.date(from:) — o método principal para converter DateComponents em Date. Calendar interpreta os componentes de acordo com seu próprio calendário e fuso horário. Se alguns campos não estiverem definidos (nil), Calendar usa valores padrão: dia = 1, hora = 0, minuto = 0, segundo = 0.
O método retorna um Date opcional — nil ocorre se os componentes se contradizem ou formam uma data inválida. Causas típicas de nil: data inexistente (32 de janeiro, 29 de fevereiro de 2023), campos contraditórios (weekday=1, day=5 no mesmo conjunto), ano impossível para o calendário dado (ano 0 no calendário gregoriano).
DateComponents com timeZone — se DateComponents contém um timeZone, Calendar o usa durante a conversão. Se timeZone não for especificada, Calendar usa sua própria timeZone atual. Se Calendar.timeZone não corresponder ao fuso horário esperado da data, o resultado pode diferir em várias horas — certifique-se de que timeZone esteja explicitamente definida em um dos objetos.
let calendar = Calendar(identifier: .gregorian)
// Criação de Date a partir de DateComponents
var comps = DateComponents()
comps.year = 2026
comps.month = 12
comps.day = 25
comps.hour = 10
if let date = calendar.date(from: comps) {
print("Christmas: \(date)")
}
// Criação especificando timeZone
calendar.timeZone = TimeZone(identifier: "UTC")!
let utcComps = DateComponents(
calendar: calendar, year: 2026, month: 7, day: 21,
hour: 12
)
let utcDate = calendar.date(from: utcComps)!
Calendar.dateComponents para diferença de datas — outro caso de uso do DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) retorna a diferença em anos, meses e dias entre duas datas. Esta é a maneira correta de calcular idade em vez de dividir TimeInterval pelo número de segundos em um ano, pois Calendar considera anos bissextos.
Calendar — a classe central que trabalha com DateComponents. Todas as operações de extração, montagem e comparação de datas passam pelo Calendar. Sem Calendar, DateComponents é apenas um conjunto de números sem significado temporal. Calendar dá aos componentes sua interpretação: determina que o mês 2 é fevereiro e que weekday 2 é segunda-feira.
Calendar.nextDate e Calendar.enumerateDates — dois métodos baseados em DateComponents. nextDate(after: Date(), matching: DateComponents) encontra a próxima data que corresponde aos componentes especificados — por exemplo, a próxima segunda-feira depois de hoje. enumerateDates(startingAfter:matching:matchingPolicy:using:) itera sobre todas as datas que correspondem ao padrão até o limite especificado.
Calendar.dateInterval — um método que retorna um DateInterval para o componente especificado. dateInterval(of: .month, for: Date()) retorna o início e o fim do mês atual. Internamente, este método usa DateComponents para encontrar os limites do período: cria DateComponents com o primeiro e último dia do mês e os converte em Date via Calendar.
let calendar = Calendar.current
// Próxima segunda-feira
let nextMonday = calendar.nextDate(
after: Date(),
matching: DateComponents(weekday: 2),
matchingPolicy: .nextTime
)!
// Diferença entre datas em dias
let diff = calendar.dateComponents(
[.day], from: Date(), to: nextMonday
)
// Intervalo do mês
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end
MatchingPolicy — um parâmetro importante dos métodos Calendar ao trabalhar com DateComponents. strictPolicy exige correspondência exata de todos os componentes, nextTimePolicy seleciona a próxima correspondência no tempo, nextTimePreservingSmallerComponents preserva os componentes menores (minutos, segundos) da data de origem. A escolha da política afeta o resultado da busca de datas, especialmente ao deslocar através de mudanças de horário de verão.
Vamos explorar casos de uso práticos de DateComponents em uma aplicação. Cada exemplo demonstra uma tarefa típica que um desenvolvedor iOS enfrenta ao trabalhar com datas calendárias.
Calendar.nextDate com DateComponents(day: 1) encontra o primeiro dia do próximo mês. Calendar determina automaticamente o número de dias no mês atual e avança para o próximo. Para notificações recorrentes, use enumerateDates ou Combine.Timer com uma chave Calendar.
func firstDayOfNextMonth(from date: Date) -> Date {
let calendar = Calendar.current
let comps = DateComponents(day: 1)
return calendar.nextDate(
after: date,
matching: comps,
matchingPolicy: .nextTime
)!
}
// Cálculo de idade em anos
func ageInYears(from birthDate: Date) -> Int {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[.year], from: birthDate, to: Date()
)
return ageComponents.year ?? 0
}
// Agrupamento de eventos por ano e mês
func groupEventsByMonth(_ events: [Event]) -> [String: [Event]] {
let calendar = Calendar.current
return Dictionary(grouping: events) { event in
let comps = calendar.dateComponents(
[.year, .month], from: event.date
)
return "\(comps.year!)-\(comps.month!)"
}
}
Cálculo de idade via Calendar.dateComponents([.year], from:to:) — a única maneira correta que considera anos bissextos. O cálculo baseado em TimeInterval (segundos / 31536000) dá erro para pessoas nascidas em 29 de fevereiro. Calendar determina corretamente se o aniversário ocorreu no ano atual e retorna a idade exata.
Agrupamento por ano e mês — uma tarefa comum para telas de histórico ou calendário. DateComponents serve como chave de agrupamento: extraia o ano e o mês da data do evento, forme uma chave de string e agrupe via Dictionary(grouping:). Para exibição, use DateFormatter com o template "LLLL yyyy" para um nome de mês localizado.
| Tarefa | Método Calendar | Função do DateComponents |
|---|---|---|
| Primeiro dia do mês | nextDate(after:matching:) | day: 1 |
| Cálculo de idade | dateComponents(from:to:) | [.year] da diferença |
| Agrupamento de datas | dateComponents(_:from:) | chave year + month |
| Busca de dia da semana | nextDate(after:matching:) | weekday: N |
Perguntas frequentes
Causas: data inexistente (31 de abril), campos contraditórios (weekday=1 com day=5), combinação inválida de campos para o calendário selecionado. Calendar tenta interpretar os componentes em seu sistema — se a combinação for impossível, o resultado é nil. Sempre use guard let ou if let ao converter.
Sim, através do operador ==. DateComponents implementa Equatable, comparando todos os campos. Duas estruturas são iguais se todos os seus campos forem iguais (nil == nil é considerado verdadeiro). Para comparar apenas um subconjunto de campos — extraia o mesmo conjunto via Calendar.dateComponents.
Date é um momento absoluto no tempo sem vínculo com calendário. DateComponents é um conjunto de números legíveis (ano, mês, dia) que só fazem sentido no contexto de um Calendar. Date pode ser comparado, subtraído, serializado para ISO 8601. DateComponents é uma representação intermediária para interagir com o calendário.
Defina apenas os campos year e month, deixando os demais como nil. Ao converter para Date via Calendar.date(from:), Calendar definirá automaticamente dia = 1, hora = 0, minuto = 0. O resultado é um Date correspondente ao primeiro dia do mês especificado à meia-noite.
DateComponents não armazena informações de fuso horário em seus campos — os valores dos campos (ano, mês, dia) dependem da timeZone na qual foram extraídos. Os componentes "21 de julho de 2026 14:00 MSK" e "21 de julho de 2026 10:00 UTC" representam o mesmo Date, mas os campos DateComponents são diferentes.
Resumo
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.
Leia também