Una ficha de museo puede mostrar «350 a. C.» con apenas unos caracteres. Representar ese dato correctamente en Swift exige algo más: distinguir entre el año, la era y el calendario, y evitar inventar una precisión que la pieza no tiene.
Según la documentación de Apple, Date representa un instante independiente del calendario y la zona horaria. No contiene un campo «año» ni sabe si queremos mostrar una fecha anterior a Cristo. Esa interpretación corresponde a Calendar; su representación textual, al formato elegido.
Por eso una fecha antigua no necesita otro tipo de instante. Lo que necesita es una conversión coherente entre sus componentes y ese instante.
En el calendario gregoriano, era = 0 corresponde a antes de nuestra era y era = 1 a nuestra era. El año se expresa como un entero positivo dentro de la era. Para representar 350 a. C., usamos año 350 y era 0.
Apple explica en su guía sobre fechas históricas que no existe el año cero en esta numeración: después del año 1 a. C. viene el 1 d. C. Los años negativos emplean otra convención, la astronómica, cuyo cero equivale a 1 a. C. Introducir -350 no significa simplemente «350 a. C.».
Podemos centralizar estas reglas en una función. En este ejemplo, una aplicación de archivo convierte la fecha de un documento en un Date:
import Foundation
enum ArchiveDates {
static let utc = TimeZone(secondsFromGMT: 0)!
static var calendar: Calendar {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = utc
return calendar
}
static func make(
year: Int,
month: Int,
day: Int,
beforeCommonEra: Bool
) -> Date? {
guard year > 0 else { return nil }
let era = beforeCommonEra ? 0 : 1
let components = DateComponents(
era: era, year: year, month: month, day: day
)
let calendar = Self.calendar
guard components.isValidDate(in: calendar),
let date = calendar.date(from: components)
else { return nil }
let result = calendar.dateComponents(
[.era, .year, .month, .day], from: date
)
guard result.era == era,
result.year == year,
result.month == month,
result.day == day
else { return nil }
return date
}
}
Devolver un opcional no garantiza por sí solo que la entrada sea válida. Algunas conversiones de calendario pueden normalizar componentes fuera de rango. Aquí usamos isValidDate(in:) y comprobamos que la conversión devuelve los mismos valores. Así rechazamos entradas que se hayan desplazado a otra fecha.
UTC actúa como una convención interna de representación. No implica que conozcamos la hora real del documento: permite construir y mostrar los componentes sin que la zona del dispositivo cambie el día.
Al presentar el resultado, fijamos tanto la zona como el calendario. El idioma sí puede seguir las preferencias del usuario. Date.FormatStyle permite configurar estos parámetros explícitamente:
import SwiftUI
struct ArchiveDateLabel: View {
@Environment(\.locale) private var locale
let date: Date
private var style: Date.FormatStyle {
Date.FormatStyle(
locale: locale,
calendar: ArchiveDates.calendar,
timeZone: ArchiveDates.utc
)
.day()
.month(.wide)
.year()
.era(.abbreviated)
}
var body: some View {
Text(date, format: style)
}
}
La era aparecerá con la abreviatura y posición correspondientes al idioma. Evitamos concatenar manualmente «BC» o asumir que todas las regiones usan el calendario gregoriano por defecto.
Para ordenar fechas de distintas eras, comparamos los Date, no sus números de año. El año 400 a. C. es anterior al 200 a. C., aunque 400 sea mayor. Si presentamos un intervalo, mostrar la era en ambos extremos resulta claro incluso cuando atraviesa el cambio de era. Omitir una abreviatura repetida es una decisión de presentación, no una regla del modelo.
También importa la precisión histórica. Si solo sabemos que una pieza pertenece al año 350 a. C., guardar el 1 de enero como su fecha real añade información inexistente. Podemos conservar año y era en un modelo propio, o utilizar DateComponents, cuyos campos pueden quedar sin especificar. Una fecha auxiliar para ordenar debe distinguirse del dato original.
Finalmente, un calendario gregoriano no reconstruye automáticamente el calendario usado por cada país en cada época. Apple documenta una transición fija en octubre de 1582; la adopción histórica varió entre territorios. Un archivo especializado debe conservar el calendario de origen y definir su conversión.
En SwiftUI, mostrar la fecha ocupa una línea. La fiabilidad está en el modelo: era explícita, conversión validada, calendario coherente y precisión conservada. Con esas decisiones, el texto mantiene el significado histórico del dato.