Data e hora no desenvolvimento móvel — um dos tópicos-chave na engenharia móvel. iOS usa DateFormatter e ISO8601DateFormatter, Android usa DateTimeFormatter e LocalDate do java.time. De acordo com Android Developer Docs, a escolha correta da API móvel para formatar data e hora afeta diretamente o desempenho e a exatidão da exibição em diferentes fusos horários.
Principais pontos
No iOS, a data e hora são tradicionalmente formatadas através do DateFormatter do Foundation. Esta classe converte Date em string e vice-versa usando um padrão, localidade e fuso horário especificados. O principal problema do DateFormatter — não é thread-safe e é lento de criar, por isso as instâncias devem ser armazenadas em cache no código móvel. A data no desenvolvimento móvel no iOS requer o formatador correto.
Criar um DateFormatter leva cerca de 1 milissegundo devido à análise do padrão dateFormat, carregamento da localidade e determinação do fuso horário. Ao formatar uma lista de centenas de datas, a criação repetida causa atrasos notáveis na IU. A solução — crie o formatador uma vez para todo o ecrã e reutilize-o. Para acesso multithread, use sincronização via DispatchQueue.
import Foundation
// DateFormatter em cache — criado uma vez
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
return formatter
}()
// ISO8601DateFormatter — alternativa leve
private let isoFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
let now = Date()
let formattedDate = dateFormatter.string(from: now)
// "01.07.2026 14:30"
let isoDate = isoFormatter.string(from: now)
// "2026-07-01T14:30:00.000Z"
Para o formato ISO 8601, use ISO8601DateFormatter — não requer especificação de padrão e funciona mais rápido que DateFormatter. No iOS 10+, esta classe é preferível para trabalhar com datas do servidor. Para formatos antigos, mantenha DateFormatter mas certifique-se de armazenar em cache a instância como uma propriedade estática ou singleton.
No Android, a data e hora são processadas através do pacote java.time, disponível desde a API 26. Classes principais: LocalDate (apenas data), LocalTime (apenas hora), LocalDateTime (data e hora sem fuso horário) e ZonedDateTime (com fuso horário). DateTimeFormatter — um formatador thread-safe para a plataforma móvel Android. A data em aplicações móveis é formatada através de DateTimeFormatter e LocalDate sem perda de desempenho.
LocalDate armazena data sem hora — ideal para aniversários. ZonedDateTime armazena informação completa com fuso horário. DateTimeFormatter suporta padrões predefinidos (ISO_LOCAL_DATE, ISO_DATE_TIME) e personalizados através de ofPattern. Todas as classes java.time são imutáveis e thread-safe, o que elimina condições de corrida ao trabalhar em múltiplas threads.
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId
// Criar e formatar a data atual
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)
// Trabalhar com fusos horários
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))
DateTimeFormatter é significativamente mais eficiente que SimpleDateFormat porque não analisa o padrão em cada chamada. Recomenda-se criar constantes de formatador ao nível da classe ou objeto companheiro. Para converter Unix Timestamp, use Instant.ofEpochSecond, depois converta para LocalDateTime ou ZonedDateTime através do fuso horário.
A data e hora corretas no ecrã do utilizador dependem do processamento adequado dos fusos horários. A data e hora no desenvolvimento móvel para Android requer consideração do fuso horário do dispositivo. A regra de ouro: armazene a hora em UTC, converta para o fuso horário local apenas para exibição. O iOS fornece TimeZone do Foundation, o Android fornece ZoneId do java.time. Ambas as APIs para plataformas móveis suportam a deteção automática do fuso horário atual do dispositivo. A data numa aplicação móvel depende de ZoneId e TimeZone.
O horário de verão cria ambiguidade: um momento no tempo pode ser representado por duas horas locais diferentes. java.time e Foundation lidam com o DST automaticamente. Use identificadores IANA (Europe/Moscow, America/New_York), não abreviaturas (MSK, EST) — as abreviaturas são ambíguas e ignoram a transição para o horário de verão.
import Foundation
// Converter UTC para hora local no iOS
func formatToLocalTime(utcDate: Date, timeZoneId: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.timeZone = TimeZone(identifier: timeZoneId)
return formatter.string(from: utcDate)
}
// Determinar o fuso horário do dispositivo
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()
No Android, use ZoneId.systemDefault() para obter o fuso horário do dispositivo. Ao converter UTC para hora local, crie um ZonedDateTime com ZoneOffset.UTC e aplique withZoneSameInstant. Para APIs antigas sem java.time, use TimeZone.getDefault() e Calendar — mas é melhor adicionar diretamente o ThreeTenABP.
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId
// Converter Unix Timestamp para hora local
fun toLocalDisplay(unixSeconds: Long): String {
val instant = Instant.ofEpochSecond(unixSeconds)
val local = instant.atZone(ZoneId.systemDefault())
return local.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
}
ThreeTenABP — uma biblioteca adaptadora que porta o java.time para Android API abaixo de 26. Fornece as mesmas classes: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Se a aplicação suporta Android 5 ou 6 (API 21-25), o ThreeTenABP é a única maneira de usar uma API móvel moderna sem migrar para o obsoleto Calendar. A data e hora no desenvolvimento móvel para dispositivos antigos é implementada através desta biblioteca. Para dispositivos antigos, a data e hora são implementadas através do ThreeTenABP.
A biblioteca requer inicialização no método Application.onCreate() chamando AndroidThreeTen.init(). Isto carrega os dados de fuso horário dos assets. Após a inicialização, a API é totalmente idêntica ao java.time — o código para API 26+ e API 21+ será o mesmo. O tamanho da biblioteca é de cerca de 400 KB, o que é aceitável para a maioria das aplicações móveis.
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter
// Inicialização em Application
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// API é idêntica ao java.time
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)
O desempenho do ThreeTenABP é comparável ao java.time original em dispositivos modernos. Em dispositivos antigos, pode haver um atraso na primeira chamada devido ao carregamento dos dados de fuso horário. Migre o código existente de Calendar para ThreeTenABP gradualmente: substitua Date e Calendar por Instant e LocalDate nos novos módulos, deixando o código antigo inalterado.
Unix Timestamp — o número de segundos decorridos desde 1 de janeiro de 1970 00:00 UTC. Este é um formato universal para armazenar e trocar tempo entre servidor e cliente. No entanto, a hora no dispositivo pode diferir da hora real devido às configurações do utilizador. Para sincronização, é usado o NTP — um protocolo de tempo preciso sobre UDP. Unix Timestamp é o formato no qual a data e hora são armazenadas no servidor.
Date().timeIntervalSince1970 no iOS retorna segundos desde 1970. No Android, System.currentTimeMillis() retorna milissegundos. Para precisão, use NTP: a biblioteca TrueTime para iOS e AndroidNtp para Android enviam um pedido a um servidor NTP e calculam o desvio de tempo. A precisão do NTP é de 1-10 ms numa rede local e 10-100 ms através da internet.
import Foundation
// Obter Unix Timestamp no iOS
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)
// Sincronização NTP com TrueTime
TrueTime.shared.start { result in
switch result {
case .success:
let ntpTime = TrueTime.shared.now()
print("Hora exata: \(ntpTime)")
case .failure(let error):
print("Erro NTP: \(error)")
}
}
Sem sincronização numa aplicação móvel, são possíveis erros: carimbos de data/hora incorretos de eventos, dessincronização com o servidor. O tempo no desenvolvimento móvel é sincronizado via NTP uma vez no arranque da aplicação, após o qual o desvio calculado é usado. Para aplicações móveis críticas em precisão (finanças, logística), o protocolo NTP é obrigatório antes de enviar dados para o servidor.
Perguntas frequentes
DateFormatter analisa o padrão de formatação, carrega a localidade e determina o fuso horário cada vez que uma instância é criada. Armazene em cache o formatador como uma constante estática ou use ISO8601DateFormatter para ISO 8601 — é mais leve e rápido.
DateTimeFormatter do pacote java.time — thread-safe e eficiente. Disponível desde a API 26. Para versões antigas, use ThreeTenABP, que fornece uma API idêntica.
Adicione ThreeTenABP — um backport do java.time para Android API 21+. Inicialize através de AndroidThreeTen.init() em Application.onCreate(). A API é totalmente idêntica ao java.time original.
Sim, armazene a hora em UTC no servidor e na base de dados local. Converta para o fuso horário local do utilizador apenas na fase de exibição. Isto elimina erros ao mudar de fuso horário ou viajar.
Date().timeIntervalSince1970 retorna o número de segundos desde 1 de janeiro de 1970. Para milissegundos, multiplique por 1000 e converta para Int64. Para sincronização precisa, use a biblioteca TrueTime com um servidor NTP.
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.