TimeZone é uma classe Foundation no iOS e macOS que abstrai informações de fuso horário para conversão correta de tempo entre regiões geográficas. De acordo com Apple Developer Documentation, 2024, TimeZone fornece métodos para trabalhar com identificadores de fuso horário (IANA Time Zone Database), deslocamentos em relação ao UTC e regras de horário de verão. A classe é integrada com DateFormatter e Calendar, garantindo a aplicação automática do fuso horário correto ao formatar datas. Ao contrário do cálculo manual de deslocamento, o TimeZone atualiza automaticamente os dados quando o fuso horário do dispositivo é alterado.
Pontos principais
TimeZone é um tipo de valor em Swift que fornece informações sobre um fuso horário geográfico: deslocamento UTC, nome, abreviação e regras de horário de verão. Em Objective-C, a classe é chamada NSTimeZone. Ambas as classes se baseiam no IANA Time Zone Database (também conhecido como banco de dados Olson), que contém o histórico de mudanças de fusos horários desde 1970.
Cada instância do TimeZone armazena um identificador de fuso horário (por exemplo, Europe/Moscow), o deslocamento atual em segundos do UTC, a flag isDaylightSavingTime e a data da próxima transição. O identificador é a chave primária: ao inicializar TimeZone(identifier:), o sistema carrega o registro correspondente do banco de dados de fusos horários do dispositivo.
De acordo com IANA (2024), o banco de dados contém mais de 600 identificadores únicos de fusos horários. A Apple fornece um snapshot deste banco de dados com cada versão do iOS e macOS, garantindo cálculos consistentes em todos os dispositivos sem a necessidade de solicitações de rede.
Arquitetura do TimeZone no Foundation é construída em um sistema de dois níveis: o identificador de fuso horário (nome legível) e sua representação numérica (deslocamento UTC). O sistema seleciona automaticamente o fuso horário atual das configurações do dispositivo, mas o desenvolvedor pode sobrescrevê-lo para operações de formatação específicas.
TimeZone está intimamente ligado ao Calendar e DateFormatter. Ao formatar uma data, o DateFormatter usa a propriedade timeZone de uma instância do TimeZone para converter um momento absoluto no tempo (Date) em uma representação de string no fuso horário desejado. Se timeZone não for definido, o fuso horário padrão do sistema é usado — TimeZone.current.
| Tipo | Inicialização | Características |
|---|---|---|
| Atual | TimeZone.current | Atualiza automaticamente ao mudar a região nas configurações, rastreia horário de verão |
| Fixo | TimeZone(identifier:) | Independente da região do dispositivo. Aplica consistentemente o identificador selecionado |
| UTC | TimeZone(secondsFromGMT: 0) | Fuso horário sem correção. Identificador: GMT |
| Com deslocamento arbitrário | TimeZone(secondsFromGMT: 10800) | Deslocamento fixo em segundos. Não considera horário de verão |
Nota importante: TimeZone(identifier:) retorna nil para identificadores desconhecidos. Esta é uma causa comum de falhas no aplicativo — os desenvolvedores esquecem de tratar o valor opcional ao passar um identificador inválido da entrada do usuário. Para identificadores IANA, maiúsculas/minúsculas importam: Europe/Moscow é válido, europe/moscow retorna nil.
O IANA Time Zone Database usa o formato “Região/Cidade” (Continente/Cidade), onde a região é um dos continentes (Africa, America, Asia, Atlantic, Australia, Europe, Indian, Pacific) ou um oceano, e a cidade é a localidade mais populosa dentro da área de cobertura do fuso horário. Este formato garante a singularidade e legibilidade do identificador.
Além do formato principal, o TimeZone suporta três métodos adicionais de identificação: abreviações (MSK, EST, PST), códigos de três letras de fusos horários (GMT, UTC) e deslocamentos numéricos (+0300, -0500). No entanto, as abreviações são ambíguas: EST pode significar Eastern Standard Time (GMT-5) ou Eastern Summer Time (GMT+10) na Austrália. A Apple recomenda usar apenas identificadores IANA.
import Foundation
// Obter todos os identificadores de fuso horário conhecidos
let allIdentifiers: [String] = TimeZone.knownTimeZoneIdentifiers
print("Total de fusos horários: \(allIdentifiers.count)")
// Filtrar por região
let europeZones = allIdentifiers.filter { $0.hasPrefix("Europe/") }
print("Fusos horários europeus: \(europeZones)")
// Abreviações (não recomendado para produção)
if let moscowTimeZone = TimeZone(abbreviation: "MSK") {
print("Segundos MSK do GMT: \(moscowTimeZone.secondsFromGMT())")
}
// Encontrar identificador por deslocamento
let utcPlus3 = TimeZone(secondsFromGMT: 10800)
print("Identificador: \(utcPlus3.identifier)")
Abreviações em TimeZone.abbreviationDictionary contêm abreviações para todos os fusos horários conhecidos, mas este dicionário não garante singularidade: a chave PST pode corresponder a America/Los_Angeles ou Pacific/Pago_Pago. Para código de produção, sempre use identificadores IANA.
TimeZone considera automaticamente as transições de horário de verão (DST) para todas as regiões onde é observado. O sistema usa dados históricos do IANA Time Zone Database, que inclui datas precisas de transição para cada fuso horário. A propriedade isDaylightSavingTime retorna true se o fuso horário está atualmente em horário de verão.
O método nextDaylightSavingTimeTransition permite saber a data da próxima transição, útil para planejar eventos futuros. Esta funcionalidade é especialmente importante para regiões com mudanças frequentes nas regras de DST, como Brasil ou Marrocos — até 2024, o Brasil mudava as datas de transição anualmente, e o cálculo manual levava a erros em aplicativos.
De acordo com Apple WWDC 2023, a biblioteca ICU (International Components for Unicode), que fundamenta o Foundation, atualiza os dados de DST a cada atualização do iOS. Os aplicativos não devem armazenar em cache os dados de horário de verão por mais de um dia após uma atualização do sistema — o banco de dados IANA pode mudar mesmo sem uma atualização da versão do SO por meio de ajustes de fusos horários.
import Foundation
// Verificar DST para Europe/Moscow
let moscow = TimeZone(identifier: "Europe/Moscow")!
let now = Date()
let isMoscowDST = moscow.isDaylightSavingTime(for: now)
print("Moscou atualmente em DST: \(isMoscowDST)")
// Obter data da próxima transição DST
if let nextTransition = moscow.nextDaylightSavingTimeTransition(
after: now
) {
let dstOffset = moscow.daylightSavingTimeOffset(
for: nextTransition
)
print("Próxima transição: \(nextTransition), deslocamento DST: \(dstOffset)s")
}
// Conversão segura com ciência de DST
let newYork = TimeZone(identifier: "America/New_York")!
let offsetNY = newYork.secondsFromGMT(for: now)
print("Deslocamento atual de NY: \(offsetNY / 3600)h")
Nuance crítica: secondsFromGMT(for:) considera DST para a data especificada, enquanto secondsFromGMT() se aplica apenas ao horário atual. Ao formatar datas históricas, sempre use a versão com o parâmetro Date: secondsFromGMT(for: someHistoricalDate). A diferença pode ser de 1 a 2 horas, o que é crítico para logs ou dados históricos.
Formatar uma data com um fuso horário específico é a tarefa mais comum ao trabalhar com TimeZone. DateFormatter usa a propriedade timeZone para converter um Date em uma string. Se timeZone não for definido explicitamente, o formatador usa TimeZone.current — o fuso horário definido no dispositivo do usuário, o que pode levar a resultados inesperados para dados do servidor.
import Foundation
// Formatar data em fuso horário específico
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let tokyo = TimeZone(identifier: "Asia/Tokyo")!
formatter.timeZone = tokyo
let tokyoTime = formatter.string(from: Date())
print("Horário de Tóquio: \(tokyoTime)")
// Identificadores disponíveis para seleção do usuário
let displayNames: [(String, String)] = TimeZone.knownTimeZoneIdentifiers
.prefix(20)
.map { ($0, TimeZone(identifier: $0)!.localizedName(
for: .generic, locale: .current
)) }
// Comparar dois fusos horários
let london = TimeZone(identifier: "Europe/London")!
let difference = tokyo.secondsFromGMT(for: Date())
- london.secondsFromGMT(for: Date())
print("Diferença Tóquio-Londres: \(difference / 3600)h")
// Trabalhar com dicionário de abreviações
let knownAbbrevs = TimeZone.abbreviationDictionary
for (abbr, ident) in knownAbbrevs.sorted(by: { $0.key < $1.key }).prefix(5) {
print("\(abbr) -> \(ident)")
}
Nome localizado de um fuso horário através de localizedName(for:locale:) retorna um nome legível no idioma especificado. Por exemplo, para Europe/Moscow com localidade russa, o método retorna o nome russo “Moskva”, e com localidade inglesa — “Moscow Time”. Estilos disponíveis: .standard (nome padrão), .daylightSaving (horário de verão) e .shortGeneric (curto).
import Foundation
let paris = TimeZone(identifier: "Europe/Paris")!
let nameRU = paris.localizedName(
for: .standard,
locale: Locale(identifier: "ru_RU")
)
print("Nome em russo: \(nameRU)")
// Verificar se a região está no mesmo dia
let isSameDay = Calendar.current.isDate(
Date(),
equalTo: Date(),
toGranularity: .day
)
print("Mesmo dia em fusos horários diferentes: \(isSameDay)")
Serialização do identificador de fuso horário é a melhor prática para armazenar TimeZone em bancos de dados ou UserDefaults. Salve o identificador (uma string como Europe/Moscow), não o deslocamento em segundos ou uma abreviação. O deslocamento pode mudar com alterações de DST, e as abreviações são ambíguas. Restauração: TimeZone(identifier: savedString).
Usar um deslocamento fixo em vez de um identificador de fuso horário é o erro mais comum. TimeZone(secondsFromGMT: 10800) não considera DST, portanto, para Europe/Moscow no verão, esta construção dá um deslocamento incorreto de 1 hora. Sempre use o identificador IANA para regiões com horário de verão.
Tratamento de nil esquecido ao inicializar TimeZone(identifier:) é o segundo erro mais frequente. Se um usuário inserir um identificador incorreto (por exemplo, “moscow” em vez de “Europe/Moscow”), o construtor retorna nil. Sem tratar o valor opcional, o aplicativo falha com um erro de tempo de execução. Use guard let ou TimeZone(identifier:) com um fallback conhecido.
Ignorar DST ao trabalhar com datas futuras. TimeZone.secondsFromGMT(for:) é a única maneira correta de obter o deslocamento para uma data específica. Usar secondsFromGMT() sem parâmetro para datas históricas ou futuras dá o deslocamento para o momento atual, que pode não corresponder ao deslocamento real na data especificada, especialmente para regiões que aboliram ou introduziram DST.
De acordo com Stack Overflow (2024), cerca de 15% das perguntas sobre DateFormatter estão relacionadas à configuração incorreta de timeZone. Um cenário típico: o servidor envia uma data em UTC, o desenvolvedor a formata sem definir o timeZone do formatador, e a data é exibida no fuso horário do dispositivo, criando confusão entre usuários de diferentes regiões. Regra: sempre defina explicitamente o timeZone do formatador para dados do servidor.
Perguntas frequentes
TimeZone é uma classe Foundation para trabalhar com fusos horários no iOS e macOS. Ela fornece informações sobre deslocamento UTC, regras de horário de verão e identificadores de fusos horários baseados no IANA Time Zone Database.
Três formatos: identificadores IANA (Europe/Moscow), abreviações (MSK, EST) e deslocamentos numéricos (+0300). A Apple recomenda usar identificadores IANA como o único formato inequívoco para código de produção.
Automaticamente através dos métodos secondsFromGMT(for:) e isDaylightSavingTime(for:). O TimeZone usa dados históricos da IANA, atualizados a cada versão do iOS, garantindo transições DST corretas para qualquer data.
TimeZone.current retorna o fuso horário selecionado pelo usuário nas configurações (pode diferir do geográfico). TimeZone.system retorna o fuso horário do dispositivo, que é determinado automaticamente por geolocalização e não pode ser sobrescrito pelo usuário.
TimeZone.current retorna o fuso horário atual do dispositivo. Para obter o identificador, use a propriedade identifier: TimeZone.current.identifier. Para um nome localizado, chame localizedName(for:locale:).
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