DateFormatter: Conceptos clave, formato de fecha y localización

Autor: IT Sectr Publicado: 2026-07-12 Tiempo de lectura: 7 min

DateFormatter es una clase de Foundation diseñada para la conversión bidireccional entre objetos Date y su representación en cadena. La clase tiene en cuenta la configuración regional, la zona horaria y el calendario del usuario, garantizando una visualización correcta de las fechas en cualquier región del mundo. Según la documentación para desarrolladores de Apple (2025), DateFormatter admite cuatro estilos predefinidos de fecha y hora, así como formatos completamente personalizados mediante una cadena de plantilla. Sin DateFormatter es imposible mostrar correctamente una fecha al usuario en una aplicación internacionalizada.

Puntos clave

  • DateFormatter — una clase para convertir Date a cadena y viceversa con soporte de configuración regional y zona horaria.
  • dateStyle y timeStyle — estilos predefinidos (.short, .medium, .long, .full) para formateo rápido.
  • dateFormat — una cadena de plantilla para formato personalizado especificada mediante símbolos Unicode LDML.
  • Locale y TimeZone — propiedades del formateador que determinan la visualización regional y la zona horaria.
  • ISO8601DateFormatter — una alternativa más rápida para el formato ISO 8601 al serializar en API.

¿Qué es DateFormatter?

DateFormatter es una clase del framework Foundation que implementa la conversión bidireccional entre Date y cadena. Apareció por primera vez en OpenStep como NSDateFormatter y desde entonces sigue siendo la herramienta principal para el formateo de fechas en todas las plataformas Apple. La clase hereda de Formatter y proporciona una API conveniente para la visualización localizada de fechas.

DateFormatter funciona basándose en patrones Unicode LDML — los mismos utilizados en ICU (International Components for Unicode). El patrón se establece mediante la propiedad dateFormat, donde los símbolos y, M, d, H, m, s corresponden a año, mes, día, horas, minutos, segundos. La repetición de un símbolo determina el formato: "y" — año de dos dígitos, "yyyy" — año de cuatro dígitos.

Crear un DateFormatter es una operación costosa, ya que durante la inicialización se cargan los datos de configuración regional y calendario. Apple recomienda crear un formateador una vez para cada tipo de formato y reutilizarlo. En SwiftUI y UIKit, los formateadores a menudo se almacenan en caché en propiedades estáticas o se crean de forma diferida en el primer acceso.

DateFormatter en iOS SDK

DateFormatter se utiliza en muchos componentes del sistema iOS. UIDatePicker usa DateFormatter internamente para mostrar fechas en modo countDownTimer. Un TextField con un formateador puede validar automáticamente las fechas introducidas por el usuario. Core Data admite atributos de tipo Date, pero su representación en cadena siempre se maneja a través de DateFormatter.

Seguridad en hilos — DateFormatter no es seguro para hilos. Modificar las propiedades del formateador desde diferentes hilos provoca un comportamiento indefinido. Para uso multi-hilo, cree instancias separadas del formateador para cada hilo o use sincronización mediante NSLock o una cola serial.

Estilos de formato de DateFormatter

dateStyle y timeStyle son las formas más sencillas de configurar la visualización de fechas. Cada estilo tiene cuatro variantes: .short, .medium, .long, .full. La combinación de dateStyle y timeStyle permite configurar de forma independiente el formato de fecha y hora, y la propiedad .none desactiva la parte correspondiente.

Para la configuración regional de EE. UU., .short formatea la fecha como "7/21/26", y para la rusa como "21.07.2026". El estilo .long para la configuración regional rusa muestra "21 de julio de 2026", y .full muestra "martes, 21 de julio de 2026" con el día de la semana. Los cuatro estilos se adaptan automáticamente a los estándares regionales, incluido el orden de los componentes y los separadores.

SFDateFormatter en iOS 15+ proporciona un enfoque alternativo mediante RelativeDateFormatter y DateIntervalFormatter. RelativeDateFormatter muestra "hoy", "ayer", "en 3 días" para contexto inmediato. DateIntervalFormatter muestra rangos de fechas: "21–25 de julio de 2026" — para reservas y planificación.

EstiloEjemplo (ru_RU)Ejemplo (en_US)
.short21.07.20267/21/26
.medium21 jul 2026Jul 21, 2026
.long21 de julio de 2026July 21, 2026
.fullmartes, 21 de julio de 2026Tuesday, July 21, 2026

Al combinar estilos, DateFormatter selecciona automáticamente el separador: para .short.date + .short.time el resultado podría ser "21.07.2026, 14:30". Para .full.date + .full.time — "martes, 21 de julio de 2026, 14:30:00 MSK". El separador lo gestiona la configuración regional, no el desarrollador — esto garantiza el cumplimiento de las expectativas regionales del usuario.

Formatos personalizados mediante dateFormat

dateFormat permite establecer un patrón de formato arbitrario utilizando símbolos de especificación Unicode LDML. Esto da control total sobre la visualización: se puede mostrar solo el año y el mes, o el día de la semana sin la fecha, o la hora sin segundos. El formato personalizado es indispensable para requisitos de diseño específicos.

Símbolos principales — yyyy (año: 2026), MM (mes: 07), dd (día: 21), HH (horas: 14), mm (minutos: 30), ss (segundos: 00). Para el nombre completo del mes use MMMM (julio), para abreviado — MMM (jul). Día de la semana — EEEE (martes), abreviado — E (mar).

Al usar dateFormat es importante establecer la configuración regional del formateador. Si no se establece locale, el formateador usa la configuración regional del sistema, lo que puede ser indeseable para un formato fijo en una API. Apple recomienda establecer locale = Locale(identifier: "en_US_POSIX") para un formato fijo entre regiones, especialmente al analizar fechas de respuestas del servidor.

swift
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"

// Analizando una cadena personalizada
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!

Un error en dateFormat es una de las causas comunes de fallos de la aplicación. Si el formato no coincide con la cadena, el método date(from:) devuelve nil. Use guard let o ?? para desempaquetado seguro de opcionales. Para validar el formato, pruébelo en todos los idiomas compatibles — algunos símbolos LDML funcionan de manera diferente en distintas configuraciones regionales.

Localización y TimeZone

Locale determina cómo se muestran los nombres de meses, días de la semana y qué separadores se utilizan. DateFormatter usa Locale.current por defecto, pero en algunos escenarios es necesario especificar una configuración regional concreta: para un formato fijo en registros use en_US_POSIX, para fechas del servidor — la configuración regional que coincida con el servidor.

La propiedad TimeZone determina la zona horaria para la visualización. Por defecto se usa la zona horaria del sistema, pero para aplicaciones con audiencia internacional a menudo es necesario mostrar las fechas en la zona horaria del usuario o en UTC. Cambiar timeZone solo afecta a la visualización — el valor Date permanece sin cambios.

Una característica importante: si DateFormatter se usa para analizar una cadena y la cadena contiene una indicación de zona horaria (por ejemplo, "2026-07-21T14:30:00Z" con Z para UTC), la propiedad timeZone se ignora — el formateador usa la zona horaria de la cadena. Si la zona horaria está ausente en la cadena, se aplica el timeZone del formateador.

swift
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
formatter.dateStyle = .long
formatter.timeStyle = .short

let moscowTime = formatter.string(from: Date())
// "21 July 2026, 14:30"

// Analizando sin zona horaria en la cadena
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!

AutoupdatingCurrentLocale — un tipo especial de configuración regional que se actualiza automáticamente cuando cambian los ajustes del sistema del usuario. DateFormatter lo admite por defecto. Si la aplicación se ejecuta en segundo plano y el usuario cambia el idioma del sistema, un formateador creado antes del cambio seguirá usando la configuración regional anterior — para actualizarlo es necesario crear una nueva instancia.

ISO8601DateFormatter y alternativas

ISO8601DateFormatter es un formateador especializado para trabajar con fechas en formato ISO 8601. Este formato es el estándar de facto para API REST, JSON e intercambio de datos. ISO8601DateFormatter funciona significativamente más rápido que DateFormatter porque no depende de la configuración regional y utiliza una gramática de análisis fija.

Opciones principales del formateador — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (añade milisegundos), .withTimeZone (incluye el desplazamiento de zona horaria). Combinando opciones se puede obtener cualquier variante ISO 8601: con milisegundos, con zona horaria, con solo fecha.

JSONEncoder.DateEncodingStrategy permite configurar globalmente la codificación de fechas para todos los modelos Codable. Opciones — .iso8601 (usa ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. La elección de la estrategia afecta a todo el ciclo de vida de serialización y debe ser coherente en todos los endpoints de la API.

swift
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"

// JSONEncoder con ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601

// Alternativa: JSONEncoder con formateador personalizado
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)

DateFormatter vs ISO8601DateFormatter — elija ISO8601DateFormatter para serializar y analizar fechas en API, ya que es 5-10 veces más rápido que DateFormatter y no es propenso a errores de localización. Use DateFormatter para la interfaz de usuario donde se requiere visualización localizada con nombres de meses y días en el idioma nativo del usuario.

Ejemplos de formato de fechas

Veamos escenarios reales de uso de DateFormatter en una aplicación iOS: visualización en un feed de noticias, introducción de fecha de nacimiento y exportación de un informe con fechas en diferentes zonas horarias.

Visualización de fecha de noticia en una lista

RelativeDateFormatter es óptimo para feeds de noticias. Muestra "justo ahora", "hace 5 minutos", "ayer" para noticias recientes y cambia a la fecha completa para las antiguas. El umbral de cambio se configura mediante calendar: para noticias use un umbral de 24 horas, para mensajeros — una semana.

swift
func formatRelativeDate(_ date: Date) -> String {
    let relative = RelativeDateFormatter()
    relative.unitsStyle = .full

    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    formatter.timeStyle = .short

    let daysDiff = Calendar.current.dateComponents(
        [.day], from: date, to: Date()
    ).day ?? 0

    return daysDiff < 1
        ? relative.localizedString(for: date, relativeTo: Date())
        : formatter.string(from: date)
}

Introducción de fecha de nacimiento — otro escenario común. DateFormatter se configura con un dateFormat específico "dd.MM.yyyy" y locale "ru_RU". Al analizar la cadena introducida es importante manejar posibles errores: el formateador devuelve nil para una cadena no válida. Después del análisis exitoso, la fecha se verifica para que esté dentro de un rango aceptable — no antes de 1900, no después de hoy.

Exportación de un informe con fechas requiere un formato fijo independiente de la configuración regional del usuario. Use dateFormat "yyyy-MM-dd HH:mm:ss" con locale en_US_POSIX y zona horaria UTC. Este enfoque garantiza que el archivo se abra correctamente en cualquier país independientemente de los ajustes regionales del sistema.

EscenarioFormateadorConfiguración clave
Feed de noticiasRelativeDateFormatterunitsStyle = .full
Entrada de fechaDateFormatterdateFormat + fallback
Serialización APIISO8601DateFormatterwithInternetDateTime
Exportación de informeDateFormatteren_US_POSIX + UTC

Preguntas frecuentes

¿Por qué DateFormatter devuelve nil para una cadena válida?

La razón más común — una discrepancia entre dateFormat y el formato de la cadena. Por ejemplo, el formato "dd.MM.yyyy" no analizará la cadena "2026-07-21". La segunda razón — discrepancia de configuración regional: la cadena "July 21, 2026" no se analizará con la configuración regional ru_RU. La tercera — errores tipográficos en símbolos LDML: use yyyy, no YYYY (significado diferente).

¿Debo crear un nuevo DateFormatter para cada llamada?

No. DateFormatter es un objeto pesado, su inicialización incluye la carga de datos de configuración regional. Cree una instancia por tipo de formato y reutilícela. En un entorno multi-hilo use almacenamiento local de hilo o un pool de formateadores con una cola serial para sincronización.

¿En qué se diferencia DateFormatter de RelativeDateFormatter?

DateFormatter muestra una fecha absoluta (21 de julio de 2026), mientras que RelativeDateFormatter muestra una relativa (hoy, ayer, en 3 días). RelativeDateFormatter se introdujo en iOS 15+ y usa la misma plantilla LDML pero selecciona automáticamente la visualización relativa.

¿Cómo manejar fechas sin zona horaria de la API?

Establezca el timeZone del formateador a UTC antes de analizar. Si el servidor devuelve una fecha en hora local sin indicación de zona horaria, consulte la especificación de la API — lo más probable es que se refiera a UTC. Para ISO 8601 con Z al final, timeZone no es necesario — el formateador analiza el desplazamiento de la cadena.

¿Cómo hacer que DateFormatter sea seguro para hilos?

No use una sola instancia desde diferentes hilos sin sincronización. Cree una nueva instancia en cada hilo o use Thread.current.threadDictionary para almacenamiento. Una alternativa es NSLock con bloqueo durante la duración de string(from:) y date(from:).

Resumen

  • DateFormatter — una clase de Foundation para convertir Date a cadena y viceversa con soporte de configuración regional, zona horaria y calendario.
  • Estilos predefinidos dateStyle y timeStyle con variantes .short, .medium, .long, .full cubren la mayoría de escenarios de UI.
  • dateFormat personalizado mediante símbolos LDML da control total sobre el formato pero requiere cuidado con la localización.
  • Locale y TimeZone — propiedades necesarias para una visualización correcta: para UI — configuración regional del sistema, para API — en_US_POSIX y UTC.
  • ISO8601DateFormatter — la opción preferida para serialización de fechas en API debido a su velocidad y estabilidad.
  • DateFormatter no es seguro para hilos — use instancias separadas para cada hilo o sincronice el acceso.
  • RelativeDateFormatter (iOS 15+) — la solución óptima para mostrar fechas relativas en feeds de noticias y mensajeros.

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.

Discutir el proyecto

Lea también