Trabalho avançado com datas e horas em Swift
Trabalhar com datas e horas é uma das tarefas principais no desenvolvimento iOS/macOS. No nível básico, a maioria dos desenvolvedores conhece Date, DateFormatter e Calendar. No entanto, em um nível avançado, surgem cenários complexos: trabalho com fusos horários, alto desempenho ao fazer parsing de centenas de datas, exibição correta de tempo relativo e manipulação de formatos personalizados. Neste artigo, abordaremos técnicas avançadas de trabalho com datas em Swift que ajudarão você a escrever um código mais confiável e eficiente.
1. Otimização do parsing de datas: DateFormatter vs ISO8601DateFormatter
Uma das operações mais comuns é converter uma string em data. O DateFormatter padrão é conveniente, mas sua criação é uma operação custosa. Se você estiver fazendo parsing de centenas de datas em um loop, cada chamada a DateFormatter() cria um novo objeto, o que leva a uma queda de desempenho.
Problema: Criar DateFormatter em um loop
// ❌ Ruim: criando formatador em um loopfor dateString in dateStrings { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" if let date = formatter.date(from: dateString) { // processamento }}Solução: Cache e ISO8601DateFormatter
Para o formato ISO 8601, use ISO8601DateFormatter — ele é mais rápido e seguro para threads. Para formatos personalizados, crie o formatador uma vez e reutilize-o.
// ✅ Bom: cache do formatadorprivate let isoFormatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] return formatter}()
// Para formatos personalizadosprivate let customFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "dd.MM.yyyy HH:mm" formatter.locale = Locale(identifier: "ru_RU") formatter.timeZone = TimeZone(secondsFromGMT: 0) return formatter}()
func parseDates(_ strings: [String]) -> [Date] { return strings.compactMap { isoFormatter.date(from: $0) }}Importante: DateFormatter não é seguro para threads. Se você estiver trabalhando com multithreading, use Thread.current ou crie um formatador separado para cada thread.
2. Trabalho com fusos horários e DateComponents
O trabalho avançado com datas requer consideração dos fusos horários. Date em Swift é um momento absoluto no tempo (número de segundos desde 1º de janeiro de 2001). Todas as informações sobre fuso horário residem em Calendar e DateFormatter.
Extraindo componentes de data em um fuso horário específico
let date = Date()let calendar = Calendar.currentlet timeZone = TimeZone(identifier: "America/New_York")!
// Obtendo componentes para o fuso horário especificadovar components = calendar.dateComponents(in: timeZone, from: date)components.hour // hora em Nova Yorkcomponents.day // dia em Nova York
// Criando uma data a partir de componentes com timeZone explícitovar newComponents = DateComponents()newComponents.year = 2024newComponents.month = 12newComponents.day = 25newComponents.hour = 10newComponents.minute = 30newComponents.timeZone = TimeZone(identifier: "Europe/Moscow")
let christmasDate = calendar.date(from: newComponents)print(christmasDate!) // 2024-12-25 07:30:00 +0000 (UTC)Comparando datas com consideração do calendário
Use compare(_:to:toGranularity:) para comparar com precisão de dia, hora ou minuto:
let date1 = Date()let date2 = Date().addingTimeInterval(3600) // +1 hora
let result = calendar.compare(date1, to: date2, toGranularity: .hour)// .orderedSame, se na mesma hora// .orderedAscending, se date1 for anterior<