Para formatear un instante de publicación en otra zona horaria, conserva el instante original e indica la zona de destino al formateador. Esta guía de Terminal para Mac genera una etiqueta de publicación legible sin analizar texto mostrado ni sumar horas manualmente.
¿Qué información necesitas antes de convertir?
Supongamos que estás preparando un documento en tu Mac y recibes la marca de tiempo de publicación sintética 2025-07-15T00:30:00Z. Necesitas la fecha y hora de publicación tal como se muestran en America/Los_Angeles. La tarea consiste en describir ese mismo momento usando la fecha del calendario y la hora del reloj del destino.
Cuatro términos determinan si tienes suficiente información:
| Término | Ejemplo sintético | Significado para esta tarea |
|---|---|---|
| Fecha civil | 2025-07-15 |
Un día del calendario, sin hora ni zona |
| Instante | El momento representado por 2025-07-15T00:30:00Z |
El punto en el tiempo que conservas |
| Desfase UTC | -07:00 |
La diferencia entre la hora local y UTC en un instante determinado |
| Zona horaria con nombre | America/Los_Angeles |
Reglas usadas para determinar el desfase aplicable |
RFC 3339 define las marcas de tiempo que contienen una fecha completa, una hora y un desfase UTC. RFC 9557 explica la distinción adicional: una zona con nombre proporciona reglas que asignan un desfase a un instante, mientras que el desfase numérico de una marca de tiempo por sí solo no describe cómo se comporta el desfase de una ubicación en otros momentos. RFC 3339, sección 5.6, RFC 9557, sección 1.2.
Usa esta decisión sobre la entrada antes de hacer cualquier conversión:
- Ya tienes un
Datede Foundation: pásalo directamente a un formateador configurado para la zona de destino. - Tienes una marca de tiempo con
Zo un desfase numérico explícito: analiza esa marca de tiempo original una vez y luego formatea el instante resultante. - Solo tienes una fecha civil: consérvala como fecha, salvo que la tarea proporcione explícitamente una hora y una zona.
- Tienes una fecha y hora local sin desfase: obtén la zona de origen y resuelve cualquier ambigüedad antes de tratarla como un instante.
Por ejemplo, 2025-07-15 no permite saber si la publicación ocurrió antes o después de la medianoche en otra zona. Asignarle la medianoche introduciría una suposición. Del mismo modo, una hora local puede corresponder a cero o varios instantes durante una transición de desfase; RFC 9557 documenta ese límite. Convertir un instante ya establecido evita ese problema de asignación inversa. RFC 9557, sección 1.2.
¿Por qué deberías evitar volver a analizar el texto mostrado?
Apple define el Date de Foundation como un punto específico en el tiempo, independiente de cualquier calendario o zona horaria. Su valor no tiene que convertirse en un Date diferente para mostrarse en otra zona. El formato proporciona el calendario y la zona necesarios para generar texto. Date.
Una etiqueta mostrada puede omitir información. Si formateas un instante como una fecha sin hora y luego analizas esa etiqueta, la hora que falta no puede recuperarse a partir de ella. La documentación de formato de Apple muestra una conversión de ida y vuelta solo con la fecha que reconstruye la medianoche. Esto es útil cuando se pretende usar la medianoche, pero no conserva un instante de publicación arbitrario. Date.FormatStyle.
Mantén la operación en este orden:
- Lee la marca de tiempo original u obtén el
Dateexistente. - Conserva ese instante como valor de trabajo.
- Elige la zona de destino, el calendario y la configuración regional de visualización.
- Formatea el instante conservado en la etiqueta final.
Sumar un desfase manualmente también cambia la tarea. Apple documenta addingTimeInterval(_:) como la creación de una fecha nueva al añadir tiempo transcurrido. Por tanto, sumar siete horas produce otro instante; elegir la zona de un formateador cambia la representación del instante original. Date.
Ejecuta un ejemplo completo de hora de publicación en tu Mac
El ejemplo requiere macOS 12 o posterior, donde está disponible la API Date.FormatStyle de Apple, y una cadena de herramientas de Swift funcional. Usa Foundation, sin paquetes adicionales. Date.FormatStyle.
Abre Terminal y comprueba la cadena de herramientas:
swift --version
Si necesitas las herramientas de línea de comandos de Apple, ejecuta el siguiente comando y completa el cuadro de diálogo de instalación. Apple documenta esta vía de instalación y señala que una instalación completa de Xcode ya incluye las herramientas de línea de comandos. Luego, repite la comprobación de versión. Instalar las herramientas de línea de comandos.
xcode-select --install
En TextEdit, crea un documento nuevo y selecciona Formato > Convertir en texto sin formato. Pega el programa Swift completo que aparece abajo y guárdalo en el Escritorio como publication-time.swift. Asegúrate de que el nombre del archivo resultante termine en .swift, sin una extensión .txt añadida. La guía de TextEdit de Apple documenta cómo crear, convertir y guardar documentos de texto sin formato. Crear, abrir y convertir documentos en TextEdit en Mac.
Este programa acepta la marca de tiempo proporcionada con precisión de segundos enteros, la analiza una vez y crea tres representaciones a partir del mismo instant. Apple documenta ISO8601DateFormatter para analizar y generar representaciones ISO 8601, y su opción withInternetDateTime para el formato RFC 3339. ISO8601DateFormatter, withInternetDateTime.
import Foundation
// Synthetic publication data. Change these two values as needed.
let sourceTimestamp = "2025-07-15T00:30:00Z"
let destinationIdentifier = "America/Los_Angeles"
enum ConversionError: Error {
case invalidTimestamp(String)
case unknownTimeZone(String)
}
let inputFormatter = ISO8601DateFormatter()
inputFormatter.formatOptions = [.withInternetDateTime]
inputFormatter.timeZone = TimeZone(secondsFromGMT: 0)
guard let instant = inputFormatter.date(from: sourceTimestamp) else {
throw ConversionError.invalidTimestamp(sourceTimestamp)
}
guard let destination = TimeZone(identifier: destinationIdentifier) else {
throw ConversionError.unknownTimeZone(destinationIdentifier)
}
let destinationFormatter = ISO8601DateFormatter()
destinationFormatter.formatOptions = [.withInternetDateTime]
destinationFormatter.timeZone = destination
let publicationLabelStyle = Date.FormatStyle(
date: .long,
time: .complete,
locale: Locale(identifier: "en_GB"),
calendar: Calendar(identifier: .gregorian),
timeZone: destination
)
let publicationDateStyle = Date.FormatStyle(
date: .long,
time: .omitted,
locale: Locale(identifier: "en_GB"),
calendar: Calendar(identifier: .gregorian),
timeZone: destination
)
print("Source instant: \(inputFormatter.string(from: instant))")
print("Destination zone: \(destination.identifier)")
print("Destination timestamp: \(destinationFormatter.string(from: instant))")
print("Publication label: \(instant.formatted(publicationLabelStyle))")
print("Publication date: \(instant.formatted(publicationDateStyle))")
Ejecuta el programa guardado:
swift "$HOME/Desktop/publication-time.swift"
Para los valores proporcionados, la marca de tiempo de destino debería ser 2025-07-14T17:30:00-07:00, y la fecha de publicación debería corresponder al 14 de julio de 2025. La etiqueta legible también incluye la hora y la información de zona; la formulación exacta y la puntuación dependen del sistema de formato.
El programa Swift se revisó con la documentación de la API consultada, pero no se ejecutó en el entorno de investigación porque Swift no estaba disponible. Las conversiones numéricas del ejemplo se comprobaron por separado con las API de fecha, hora y zona de Python.
¿Qué ajustes controlan el resultado?
El inicializador del formateador acepta ajustes independientes para la configuración regional, el calendario y la zona horaria. Aquí, en_GB solicita las convenciones de formato del inglés británico, el calendario gregoriano proporciona el sistema de fechas y destination determina la fecha y la hora local. Cambia el identificador de zona cuando necesites otro destino; cambia la configuración regional cuando necesites otra convención de presentación. init(date:time:locale:calendar:timeZone:capitalizationContext:).
El resultado que solo contiene la fecha sigue saliendo directamente de instant. Establecer time: .omitted elimina la hora de la etiqueta de salida. No requiere construir un instante nuevo a medianoche.
Comprueba los cruces de medianoche y los desfases estacionales
Usa los siguientes ejemplos sintéticos para comprobar si el resultado conserva la operación prevista. Son marcas de tiempo de publicación ilustrativas, con representaciones de destino calculadas.
| Instante original | Zona de destino | Representación de destino |
|---|---|---|
2025-01-15T00:30:00Z |
America/Los_Angeles |
2025-01-14T16:30:00-08:00 |
2025-07-15T00:30:00Z |
America/Los_Angeles |
2025-07-14T17:30:00-07:00 |
2025-07-15T00:30:00Z |
Asia/Tokyo |
2025-07-15T09:30:00+09:00 |
2025-07-15T23:30:00Z |
Asia/Tokyo |
2025-07-16T08:30:00+09:00 |
Las dos primeras filas muestran por qué un ajuste fijo no basta para un destino con nombre: su desfase aplicable puede depender del instante. Las dos últimas filas muestran por qué debes calcular la fecha completa del calendario del destino junto con la hora. Una publicación puede aparecer el día anterior, el mismo día o el siguiente.
Las zonas con nombre usan reglas de una base de datos de zonas horarias. IANA documenta que macOS usa su base de datos y que las actualizaciones suelen llegar a los clientes a través de actualizaciones del sistema operativo. Si los resultados difieren entre máquinas, comprueba sus identificadores de zona y las actualizaciones disponibles antes de modificar la marca de tiempo de origen. Datos de zonas horarias y horario de verano.
¿Qué deberías hacer si la entrada o la salida son inesperadas?
Realiza estas comprobaciones en orden:
- Confirma que el origen identifica un instante. Conserva su
Zo su desfase numérico. Un valor que solo contiene la fecha o una hora local requiere información adicional. - Confirma el identificador de destino. Usa un identificador como
America/Los_Angeles. El inicializador de Apple devuelvenilsi el identificador no se reconoce; este programa se detiene con un error en lugar de sustituirlo por otra zona. - Comprueba el formato de marca de tiempo admitido. El ejemplo está configurado para marcas de tiempo de Internet con segundos enteros. Las fracciones de segundo u otra representación de entrada requieren una configuración del analizador adecuada. Conserva la entrada original al hacer ese cambio.
- Compara la marca de tiempo numérica de destino. Usa su fecha, hora y desfase para evaluar la conversión antes de investigar la puntuación de visualización.
- Comprueba que cada resultado use el
instantoriginal. Elimina cualquier paso intermedio que formatee una etiqueta y luego la analice para la siguiente conversión. init(identifier:), ISO8601DateFormatter.
Una zona con nombre y un desfase también pueden aparecer juntos en una marca de tiempo extendida según RFC 9557. La existencia de esa norma no confirma que el analizador de este ejemplo admita anotaciones de zona entre corchetes. Mantén el identificador de destino en el valor destinationIdentifier separado que se usa arriba, salvo que implementes y verifiques deliberadamente una ruta de entrada para el formato extendido. RFC 9557.
Para una etiqueta de publicación, conserva el instante original como valor reutilizable y genera a partir de él el texto de cada destino. Así podrás cambiar la zona de destino, el idioma de visualización o los detalles visibles y mantener cada etiqueta vinculada al mismo momento de publicación.
Fuentes
- Date — Apple
- Date.FormatStyle — Apple
- init(date:time:locale:calendar:timeZone:capitalizationContext:) — Apple
- ISO8601DateFormatter — Apple
- withInternetDateTime — Apple
- init(identifier:) — Apple
- Instalar las herramientas de línea de comandos — Apple
- Crear, abrir y convertir documentos en TextEdit en Mac — Apple
- RFC 3339: Fecha y hora en Internet: marcas de tiempo — RFC Editor
- RFC 9557: Fecha y hora en Internet: marcas de tiempo con información adicional — RFC Editor
- Datos de zonas horarias y horario de verano — IANA