La fecha y hora en el desarrollo móvil — uno de los temas clave en la ingeniería móvil. iOS utiliza DateFormatter e ISO8601DateFormatter, Android utiliza DateTimeFormatter y LocalDate de java.time. Según Android Developer Docs, la elección correcta de la API móvil para formatear fecha y hora afecta directamente el rendimiento y la precisión de visualización en diferentes zonas horarias.
Puntos clave
En iOS, la fecha y hora se formatean tradicionalmente mediante DateFormatter de Foundation. Esta clase convierte Date en cadena y viceversa usando un patrón, configuración regional y zona horaria especificados. El principal problema de DateFormatter — no es seguro para subprocesos y se crea lentamente, por lo que en el código móvil las instancias deben almacenarse en caché. La fecha en el desarrollo móvil en iOS requiere el formateador adecuado.
Crear un DateFormatter toma aproximadamente 1 milisegundo debido al análisis del patrón dateFormat, la carga de la configuración regional y la determinación de la zona horaria. Al formatear una lista de cientos de fechas, la creación repetida provoca retrasos notables en la interfaz de usuario. La solución — crear el formateador una vez para toda la pantalla y reutilizarlo. Para acceso multiproceso, use sincronización mediante DispatchQueue.
import Foundation
// DateFormatter en caché — se crea una 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 ligera
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 el formato ISO 8601, use ISO8601DateFormatter — no requiere especificar un patrón y funciona más rápido que DateFormatter. En iOS 10+, esta clase es preferible para trabajar con fechas del servidor. Para formatos antiguos, mantenga DateFormatter pero asegúrese de almacenar en caché la instancia como una propiedad estática o singleton.
En Android, la fecha y hora se manejan mediante el paquete java.time, disponible desde API 26. Clases principales: LocalDate (solo fecha), LocalTime (solo hora), LocalDateTime (fecha y hora sin zona horaria) y ZonedDateTime (con zona horaria). DateTimeFormatter — un formateador seguro para subprocesos para la plataforma móvil Android. La fecha en aplicaciones móviles se formatea mediante DateTimeFormatter y LocalDate sin pérdida de rendimiento.
LocalDate almacena la fecha sin hora — ideal para cumpleaños. ZonedDateTime almacena información completa con zona horaria. DateTimeFormatter admite patrones predefinidos (ISO_LOCAL_DATE, ISO_DATE_TIME) y personalizados mediante ofPattern. Todas las clases de java.time son inmutables y seguras para subprocesos, lo que elimina las condiciones de carrera al trabajar en múltiples subprocesos.
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId
// Crear y formatear la fecha actual
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)
// Trabajar con zonas horarias
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))
DateTimeFormatter es significativamente más eficiente que SimpleDateFormat porque no analiza el patrón en cada llamada. Se recomienda crear constantes de formateador a nivel de clase o objeto complementario. Para convertir un Unix Timestamp, use Instant.ofEpochSecond, luego convierta a LocalDateTime o ZonedDateTime mediante la zona horaria.
La fecha y hora correctas en la pantalla del usuario dependen del manejo adecuado de las zonas horarias. La fecha y hora en el desarrollo móvil para Android requiere considerar la zona horaria del dispositivo. La regla de oro: almacene la hora en UTC, convierta a la zona horaria local solo para mostrar. iOS proporciona TimeZone de Foundation, Android proporciona ZoneId de java.time. Ambas API para plataformas móviles admiten la detección automática de la zona horaria actual del dispositivo. La fecha en una aplicación móvil depende de ZoneId y TimeZone.
El horario de verano crea ambigüedad: un momento en el tiempo puede representarse mediante dos horas locales diferentes. java.time y Foundation manejan el DST automáticamente. Use identificadores IANA (Europe/Moscow, America/New_York), no abreviaturas (MSK, EST) — las abreviaturas son ambiguas e ignoran el cambio al horario de verano.
import Foundation
// Convertir UTC a hora local en 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 la zona horaria del dispositivo
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()
En Android, use ZoneId.systemDefault() para obtener la zona horaria del dispositivo. Al convertir UTC a hora local, cree un ZonedDateTime con ZoneOffset.UTC y aplique withZoneSameInstant. Para API antiguas sin java.time, use TimeZone.getDefault() y Calendar — pero es mejor agregar directamente ThreeTenABP.
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId
// Convertir Unix Timestamp a 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 — una biblioteca adaptadora que porta java.time a Android API inferior a 26. Proporciona las mismas clases: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Si la aplicación es compatible con Android 5 o 6 (API 21-25), ThreeTenABP es la única forma de usar una API móvil moderna sin migrar al obsoleto Calendar. La fecha y hora en el desarrollo móvil para dispositivos antiguos se implementa mediante esta biblioteca. Para dispositivos antiguos, la fecha y hora se implementan mediante ThreeTenABP.
La biblioteca requiere inicialización en el método Application.onCreate() llamando a AndroidThreeTen.init(). Esto carga los datos de zona horaria desde assets. Después de la inicialización, la API es totalmente idéntica a java.time — el código para API 26+ y para API 21+ será el mismo. El tamaño de la biblioteca es de aproximadamente 400 KB, lo cual es aceptable para la mayoría de las aplicaciones móviles.
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter
// Inicialización en Application
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// API es idéntica a java.time
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)
El rendimiento de ThreeTenABP es comparable al java.time original en dispositivos modernos. En dispositivos antiguos, puede haber una demora en la primera llamada debido a la carga de datos de zona horaria. Migre el código existente de Calendar a ThreeTenABP gradualmente: reemplace Date y Calendar con Instant y LocalDate en los nuevos módulos, dejando el código antiguo sin cambios.
Unix Timestamp — la cantidad de segundos transcurridos desde el 1 de enero de 1970 00:00 UTC. Este es un formato universal para almacenar e intercambiar tiempo entre servidor y cliente. Sin embargo, la hora en el dispositivo puede diferir de la hora real debido a la configuración del usuario. Para la sincronización se utiliza NTP — un protocolo de tiempo preciso sobre UDP. Unix Timestamp es el formato en el que se almacenan la fecha y hora en el servidor.
Date().timeIntervalSince1970 en iOS devuelve segundos desde 1970. En Android, System.currentTimeMillis() devuelve milisegundos. Para precisión, use NTP: la biblioteca TrueTime para iOS y AndroidNtp para Android envían una solicitud a un servidor NTP y calculan el desplazamiento horario. La precisión de NTP es de 1-10 ms en una red local y de 10-100 ms a través de Internet.
import Foundation
// Obtener Unix Timestamp en iOS
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)
// Sincronización NTP con TrueTime
TrueTime.shared.start { result in
switch result {
case .success:
let ntpTime = TrueTime.shared.now()
print("Hora exacta: \(ntpTime)")
case .failure(let error):
print("Error NTP: \(error)")
}
}
Sin sincronización en una aplicación móvil, son posibles errores: marcas de tiempo incorrectas de eventos, desincronización con el servidor. El tiempo en el desarrollo móvil se sincroniza mediante NTP una vez al iniciar la aplicación, después de lo cual se utiliza el desplazamiento calculado. Para aplicaciones móviles críticas en cuanto a precisión (finanzas, logística), el protocolo NTP es obligatorio antes de enviar datos al servidor.
Preguntas frecuentes
DateFormatter analiza el patrón de formato, carga la configuración regional y determina la zona horaria cada vez que se crea una instancia. Almacene en caché el formateador como una constante estática o use ISO8601DateFormatter para ISO 8601 — es más ligero y rápido.
DateTimeFormatter del paquete java.time — seguro para subprocesos y eficiente. Disponible desde API 26. Para versiones antiguas, use ThreeTenABP, que proporciona una API idéntica.
Agregue ThreeTenABP — un backport de java.time para Android API 21+. Inicialice mediante AndroidThreeTen.init() en Application.onCreate(). La API es totalmente idéntica al java.time original.
Sí, almacene la hora en UTC en el servidor y en la base de datos local. Convierta a la zona horaria local del usuario solo en la etapa de visualización. Esto elimina errores al cambiar de zona horaria o viajar.
Date().timeIntervalSince1970 devuelve el número de segundos desde el 1 de enero de 1970. Para milisegundos, multiplique por 1000 y convierta a Int64. Para sincronización precisa, use la biblioteca TrueTime con un servidor NTP.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.