DateIntervalFormatter es una clase de Foundation en iOS y macOS diseñada para formatear rangos de fechas en cadenas localizadas: “21–25 de julio de 2024”, “del 21 al 25 de julio de 2024” o “Jul 21–25, 2024”. Según Apple Developer Documentation, 2024, DateIntervalFormatter determina automáticamente qué componentes de fecha repetir (si el rango está dentro de un mes, el mes se muestra una vez) y localiza los separadores y el orden de las palabras. A diferencia de la concatenación manual de dos fechas formateadas, esta clase tiene en cuenta las reglas gramaticales del idioma. La clase está disponible desde iOS 8 y macOS 10.10.
Puntos clave
DateIntervalFormatter es una subclase de Formatter en Foundation que toma un objeto DateInterval (un rango entre dos fechas) y devuelve una cadena localizada que describe ese rango. Por ejemplo, para el rango del 21 al 25 de julio de 2024, el resultado sería “21–25 de julio de 2024” para es_ES. La clase agrupa inteligentemente los elementos repetidos: si ambas fechas están en el mismo mes, el nombre del mes se muestra una vez.
El valor principal de DateIntervalFormatter es el manejo automático de la gramática de rangos. Al formatear manualmente, un desarrollador tendría que comparar el mes/año de inicio y fin, elegir un separador (guion, “al”, “bis”) y gestionar la declinación. DateIntervalFormatter hace esto automáticamente basándose en los datos de CLDR (Common Locale Data Repository), reduciendo errores en aplicaciones internacionales, especialmente para idiomas con gramática compleja.
Según Unicode CLDR v44 (2024), las reglas de formato de intervalos de fecha varían significativamente entre idiomas. El alemán usa la preposición “bis” (21.–25. Juli 2024), el francés usa “au” (du 21 au 25 juillet 2024), el japonés usa un guion (2024 Jul 21–25). DateIntervalFormatter cubre todas estas variaciones sin código adicional del desarrollador.
El principio de funcionamiento de DateIntervalFormatter se basa en analizar dos fechas que forman un rango y seleccionar la representación textual óptima considerando la configuración regional. La clase compara los componentes de fecha (año, mes, día) y toma decisiones de agrupación: si el año es el mismo, se muestra una vez; si el mes es el mismo, se muestra una vez; si los días difieren, se muestra un rango de días.
| Rango | es_ES |
|---|---|
| Un día | 21 de julio de 2024 |
| Dentro del mes | 21–25 de julio de 2024 |
| Meses diferentes | 21 de julio – 5 de agosto de 2024 |
| Años diferentes | 25 de diciembre de 2024 – 5 de enero de 2025 |
| Con hora | 21 de julio de 2024, 14:30–16:45 |
Lógica de agrupación implementada basada en plantillas CLDR. El formateador verifica la igualdad de cada componente de fecha (Calendar.Component: year, month, day) en orden de mayor a menor. Una vez que un componente difiere, todos los componentes menores se muestran para ambas fechas. Por ejemplo, para el 21–25 de julio: el año coincide, el mes coincide, el día difiere → el mes se muestra una vez, los días se muestran para cada fecha.
Nota importante: DateIntervalFormatter no permite personalizar el separador a través de la API. El separador está determinado por la configuración regional y no se puede sobrescribir. Si se requiere un separador no estándar (por ejemplo, “hasta” en lugar de “al”), tendrías que formatear las fechas manualmente con DateFormatter y concatenar las cadenas con un separador personalizado.
DateIntervalFormatter proporciona dos conjuntos de estilos: dateStyle y timeStyle para cada extremo del rango. Estos estilos funcionan de manera similar a DateFormatter: .none oculta el componente, .short da un formato corto (21/07/2024), .medium (21 jul 2024), .long (21 de julio de 2024), .full (domingo, 21 de julio de 2024). Combinando dateStyle y timeStyle, se pueden obtener diferentes niveles de detalle.
Importante: dateStyle y timeStyle se aplican a ambos extremos del rango por igual. No se pueden establecer estilos diferentes para el inicio y el final (por ejemplo, .medium para el inicio y .short para el final). Si se necesitan estilos diferentes, debes formatear cada fecha con un DateFormatter independiente y concatenar los resultados.
import Foundation
let formatter = DateIntervalFormatter()
// Diferentes combinaciones de estilos
let startDate = Date()
let endDate = Date().addingTimeInterval(345600) // +4 días
let interval = DateInterval(start: startDate, end: endDate)
// Solo fecha, formato medio
formatter.dateStyle = .medium
formatter.timeStyle = .none
print("Solo fecha: \(formatter.string(from: interval))")
// Formato corto con hora
formatter.dateStyle = .short
formatter.timeStyle = .short
print("Corto con hora: \(formatter.string(from: interval))")
// Formato completo
formatter.dateStyle = .full
formatter.timeStyle = .none
print("Fecha completa: \(formatter.string(from: interval))")
Uso básico de DateIntervalFormatter incluye crear una instancia, configurar estilos y llamar a string(from:). El método acepta DateInterval, una estructura con propiedades start y end. DateInterval se puede crear a partir de dos valores Date o inicializarse con Duration (iOS 16+). Después del formateo, el resultado está listo para mostrarse en la interfaz sin procesamiento adicional.
import Foundation
let calendar = Calendar.current
let now = Date()
// Ejemplos de intervalos específicos
let examples: [(title: String, start: Date, end: Date)] = [
(
"2-hour event",
now,
now.addingTimeInterval(7200)
),
(
"Week-long vacation",
now,
now.addingTimeInterval(604800)
),
(
"Cross-year period",
calendar.date(from: DateComponents(
year: 2024, month: 12, day: 25
))!,
calendar.date(from: DateComponents(
year: 2025, month: 1, day: 5
))!
)
]
let intervalFormatter = DateIntervalFormatter()
intervalFormatter.dateStyle = .medium
intervalFormatter.timeStyle = .short
for (title, start, end) in examples {
let interval = DateInterval(start: start, end: end)
let result = intervalFormatter.string(from: interval)
print("\(title): \(result)")
}
// Formato mediante Calendar (iOS 16+)
if let nextWeek = calendar.date(
byAdding: .day, value: 7, to: now
) {
let weekInterval = DateInterval(start: now, end: nextWeek)
print("Próximos 7 días: \(intervalFormatter.string(from: weekInterval))")
}
DateIntervalFormatter y reservas de calendario: en aplicaciones de reservas (hoteles, billetes), los intervalos de fecha son un elemento clave de la interfaz. DateIntervalFormatter maneja correctamente los intervalos entre años (por ejemplo, del 28 de diciembre al 3 de enero), agrupando mes y año para cada fecha por separado. Para estos escenarios, se recomienda usar dateStyle = .medium y timeStyle = .none, el formato más legible para fechas sin hora.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
// Ejemplos de reservas
struct Booking {
let checkIn: Date
let checkOut: Date
var formattedInterval: String {
let interval = DateInterval(start: checkIn, end: checkOut)
return formatter.string(from: interval)
}
}
let booking = Booking(
checkIn: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 21
))!,
checkOut: calendar.date(from: DateComponents(
year: 2024, month: 7, day: 25
))!
)
print("Reserva: \(booking.formattedInterval)")
// Usar con diferentes configuraciones regionales
let enFormatter = DateIntervalFormatter()
enFormatter.dateStyle = .medium
enFormatter.timeStyle = .none
enFormatter.locale = Locale(identifier: "en_US")
print("Inglés: \(enFormatter.string(from: interval))")
DateInterval vs DateIntervalFormatter: DateInterval es una estructura que representa un rango de fechas (inicio y fin). DateIntervalFormatter es un formateador que convierte esta estructura en una cadena. DateInterval también admite comprobaciones contains(Date) e intersection(with:), útil para la lógica de reservas (verificar superposición de fechas).
DateIntervalFormatter localiza la salida a través de la propiedad locale. Por defecto, se usa Locale.current, la configuración regional del dispositivo. Para mostrar intervalos en otro idioma (por ejemplo, contenido en inglés con interfaz en ruso), establece la locale explícitamente. A diferencia de DateFormatter, DateIntervalFormatter no requiere configurar la locale para datos del servidor. Siempre usa su lógica de agrupación interna basada en CLDR.
Las diferencias de idioma en el formato de intervalos de fecha son significativamente más complejas que para fechas individuales. El español usa la preposición “al”: del 21 al 25 de julio. El inglés usa un guion simple: Jul 21–25. El francés usa la preposición “au”: du 21 au 25 juillet. El alemán usa un punto después del número y un guion: 21.–25. Juli. DateIntervalFormatter cubre todas estas variantes.
import Foundation
let formatter = DateIntervalFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
let start = Date()
let end = Date().addingTimeInterval(259200) // +3 días
let interval = DateInterval(start: start, end: end)
// Demostrar diferentes configuraciones regionales
let localeIds = ["ru_RU", "en_US", "de_DE", "fr_FR", "ja_JP", "zh_CN"]
for localeId in localeIds {
formatter.locale = Locale(identifier: localeId)
print("\(localeId): \(formatter.string(from: interval))")
}
// Localización para intervalos de tiempo
formatter.dateStyle = .none
formatter.timeStyle = .short
let todayStart = Date()
let todayEnd = Date().addingTimeInterval(3600)
let timeInterval = DateInterval(start: todayStart, end: todayEnd)
for localeId in ["ru_RU", "en_US", "de_DE"] {
formatter.locale = Locale(identifier: localeId)
print("\(localeId) hora: \(formatter.string(from: timeInterval))")
}
Particularidades de localización: para español, DateIntervalFormatter usa la preposición “al” para formatos largos. Para formatos cortos, usa el guion. La elección del formato depende del contexto: para una lista de reservas usa .medium, para vista detallada usa .long o .full.
DateIntervalFormatter ocupa el nicho de formateo de rangos de fechas, que no cubren otras clases de Foundation. DateFormatter formatea fechas individuales, RelativeDateTimeFormatter formatea fechas relativas (hace/dentro de), DateComponentsFormatter formatea duración (2 horas 30 minutos). Cada una de estas clases resuelve una tarea específica y no se pueden usar indistintamente.
| Clase | Propósito | Ejemplo de salida |
|---|---|---|
| DateIntervalFormatter | Rango de fechas | 21–25 de julio de 2024 |
| DateFormatter | Fecha individual | 21 de julio de 2024 |
| RelativeDateTimeFormatter | Tiempo relativo | hace 3 días |
| DateComponentsFormatter | Duración | 2 horas 30 minutos |
| ISO8601DateFormatter | Formato ISO 8601 | 2024-07-21T14:30:00Z |
Cuándo usar DateIntervalFormatter: para mostrar rangos de fechas en la interfaz — reservas de hoteles, eventos, filtrado por fechas, historial de operaciones. Para calcular la duración entre fechas, usa DateComponentsFormatter, no DateIntervalFormatter, ya que este último no está diseñado para mostrar duración. DateFormatter debe usarse solo para fechas individuales, no para concatenar dos fechas formateadas mediante concatenación de cadenas, ya que esto provoca pérdida de localización del separador.
Caso extremo: DateIntervalFormatter no admite la visualización de intervalos abiertos (sin fecha de fin). Si se desconoce el final del rango (por ejemplo, “desde el 21 de julio”), usa DateFormatter con la preposición “desde”. Además, DateIntervalFormatter no admite intervalos con hora especificada para días diferentes. La hora se aplica a cada fecha por separado, lo que puede resultar redundante para intervalos cortos.
Preguntas frecuentes
DateIntervalFormatter es una clase de Foundation para formatear rangos de fechas en cadenas localizadas. Disponible desde iOS 8, agrupa automáticamente los componentes repetidos (mes, año) y selecciona el separador correcto para el idioma.
Compara componentes desde el año hasta el día. Si el año coincide, se muestra una vez. Si el mes coincide, se muestra una vez. Los días diferentes se muestran como un rango. Esto da “21–25 de julio de 2024” en lugar de “21 de julio de 2024 – 25 de julio de 2024”.
No, el separador está determinado por la configuración regional y no se puede personalizar mediante la API. Para un separador personalizado (por ejemplo, “hasta” en lugar de “al”), formatea cada fecha con un DateFormatter independiente y concatena las cadenas manualmente.
DateIntervalFormatter formatea un rango de fechas (dos fechas) como una unidad única con agrupación de componentes. DateFormatter formatea una fecha individual. Para rangos, usa siempre DateIntervalFormatter, ya que proporciona la localización correcta del separador.
Automáticamente — DateIntervalFormatter detecta que los años difieren y muestra las fechas completas para ambos extremos: “25 de diciembre de 2024 – 5 de enero de 2025”. No se requiere configuración adicional, solo establecer dateStyle.
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.
Lea también