Para restar un número exacto de horas de una marca de tiempo UTC en tu Mac, analízala con su desplazamiento UTC, resta una duración y especifica UTC como formato de salida. Este flujo de trabajo en Terminal usa Python y una fecha de publicación sintética.

La tarea aquí es específica: atrasar una marca de tiempo de publicación un número entero no negativo de horas, manteniendo la entrada y la salida en UTC. Por ejemplo, al restar siete horas de 2026-05-12T02:30:00Z, se obtiene 2026-05-11T19:30:00Z.

«Exacto» sigue el modelo documentado de datetime de Python: una hora equivale a 3600 segundos y los segundos intercalares no se representan. Por lo tanto, este flujo de trabajo sirve para marcas de tiempo de publicación habituales; los cálculos que deban contar segundos intercalares requieren otro modelo de tiempo. Documentación de datetime de Python

¿Con qué tipo de fecha empiezas?

Antes de calcular, distingue una fecha de calendario de una marca de tiempo. Una fecha como 2026-05-12 no indica cuándo se publica algo. Añadir la medianoche o suponer la zona local de tu Mac introduciría información que la entrada nunca proporcionó.

Concepto Ejemplo sintético Qué indica
Fecha civil 2026-05-12 Un día del calendario sin hora ni desplazamiento
Fecha y hora locales 2026-05-12T02:30:00 Campos del reloj sin contexto suficiente para identificar un instante
Instante expresado en UTC 2026-05-12T02:30:00Z Un punto específico en el tiempo
Desplazamiento numérico +00:00 La diferencia indicada con respecto a UTC
Zona horaria con nombre Europe/Paris Reglas para relacionar las horas locales del reloj con UTC

Un desplazamiento y una zona con nombre cumplen funciones distintas. Un desplazamiento numérico describe la relación de una marca de tiempo con UTC; una zona con nombre proporciona reglas que pueden variar según la fecha. La RFC 9557 define estas distinciones y explica por qué algunas horas locales pueden corresponder a cero o varios instantes. RFC 9557, definiciones

Para esta tarea, usa una marca de tiempo completa. El programa que sigue acepta T en mayúsculas, segundos, una fracción de segundo opcional de uno a seis dígitos y Z o +00:00. Se trata de un subconjunto deliberadamente restringido de RFC 3339, cuya gramática de marcas de tiempo también permite otros desplazamientos y más dígitos fraccionarios. RFC 3339, formato de fecha y hora

¿Cómo se restan horas en Terminal?

Prepara Python en tu Mac

Abre Finder, ve a /Applications/Utilities y haz doble clic en Terminal. Apple documenta este método para abrir la aplicación de línea de comandos. Abrir o salir de Terminal en Mac

Introduce este comando y pulsa Return:

python3 --version

Para esta guía, usa Python 3.11 o una versión posterior. Si no tienes un intérprete adecuado, sigue las instrucciones oficiales de instalación para macOS: descarga un instalador de Python compatible desde la página de descargas de macOS enlazada, abre su archivo .pkg y completa los pasos de instalación documentados. Luego, abre una nueva ventana de Terminal y vuelve a comprobar la versión. La documentación de Python explica tanto la instalación como la ejecución de Python desde un shell. Uso de Python en macOS

Ejecuta el cálculo completo

Copia todo el bloque que sigue en Terminal, incluidas la primera y la última línea, y pulsa Return. Para hacer otro cálculo, cambia solo source_timestamp y hours_to_subtract antes de pegarlo. Mantén la marca de tiempo entre comillas e introduce las horas como un número entero.

python3 - <<'PY'
import re
from datetime import datetime, timedelta, timezone

source_timestamp = "2026-05-12T02:30:00Z"
hours_to_subtract = 7

def subtract_utc_hours(text, hours):
    if type(hours) is not int or hours < 0:
        raise ValueError("Hours must be a non-negative whole number.")

    match = re.fullmatch(
        r"[0-9]{4}-[0-9]{2}-[0-9]{2}T"
        r"[0-9]{2}:[0-9]{2}:[0-9]{2}"
        r"(?P<fraction>\.[0-9]{1,6})?(?:Z|\+00:00)",
        text,
    )
    if match is None:
        raise ValueError(
            "Use YYYY-MM-DDTHH:MM:SS, optionally .ffffff, "
            "ending in Z or +00:00."
        )

    normalized = text[:-1] + "+00:00" if text.endswith("Z") else text
    start = datetime.fromisoformat(normalized).astimezone(timezone.utc)
    try:
        result = start - timedelta(hours=hours)
    except OverflowError as exc:
        raise ValueError(
            "The duration or result is outside the supported range."
        ) from exc

    # Whole-hour subtraction leaves the fractional second unchanged.
    seconds_text = result.isoformat(timespec="seconds")
    return seconds_text[:-6] + (match.group("fraction") or "") + "Z"

try:
    print(subtract_utc_hours(source_timestamp, hours_to_subtract))
except ValueError as exc:
    raise SystemExit(f"Cannot subtract: {exc}")
PY

La salida para la marca de tiempo de publicación sintética proporcionada es:

2026-05-11T19:30:00Z

Este es un programa completo que usa la biblioteca estándar de Python. Imprime la marca de tiempo calculada sin crear ningún archivo. Copia el resultado en el campo de fecha de publicación o en el documento que estés preparando.

La secuencia de la API es datetime.fromisoformat(), la conversión a timezone.utc, la resta de timedelta(hours=hours) y la salida mediante isoformat(). Python documenta estas operaciones de análisis, zona horaria, duración y formato. API de datetime de Python

¿Cómo conserva el programa UTC y los segundos fraccionarios?

La comprobación de entrada exige una representación UTC explícita. Si una marca de tiempo no tiene desplazamiento, el programa la rechaza de inmediato, así que nunca necesita inferir una zona a partir de la configuración de tu Mac. Ambos sufijos aceptados se analizan como marcas de tiempo con desplazamiento cero, y la salida siempre se escribe con Z.

Conservar UTC no significa preservar todos los caracteres de la cadena original. Una entrada que termine en +00:00 vuelve con Z al final. El resultado mantiene la representación UTC, mientras que la fecha y la hora retroceden la duración solicitada.

El programa también conserva el texto proporcionado de los segundos fraccionarios. Al restar horas enteras, la fracción no cambia: .120 sigue siendo .120, en lugar de convertirse en .12 o desaparecer. Las entradas con más de seis dígitos fraccionarios se rechazan en lugar de acortarse.

Hay un matiz útil en los estándares: Z representa un desplazamiento UTC cero, pero no identifica la zona horaria del lugar de origen. La RFC 9557 actualiza la interpretación de Z en la RFC 3339 para permitir que se desconozca el desplazamiento local. Por diseño, este programa acepta Z y +00:00, y rechaza -00:00 como una decisión sobre la política de entrada. RFC 9557, actualización de RFC 3339

¿Cómo puedes comprobar el resultado antes de usarlo?

Empieza con un cálculo que cruce la medianoche. En el ejemplo principal, retroceder dos horas da 00:30:00 el 12 de mayo; retroceder cinco horas más da 19:30:00 el 11 de mayo. Un resultado que siga indicando el 12 de mayo sería incorrecto.

Estos ejemplos sintéticos ofrecen comprobaciones adicionales. Cambia los dos valores de entrada del programa completo para reproducir cada fila.

Entrada UTC Horas restadas Salida UTC esperada
2026-05-12T02:30:00Z 7 2026-05-11T19:30:00Z
2026-01-01T00:15:00+00:00 1 2025-12-31T23:15:00Z
2028-03-01T00:30:00Z 1 2028-02-29T23:30:00Z
2026-05-12T02:30:00.120Z 7 2026-05-11T19:30:00.120Z
2026-05-12T02:30:00Z 0 2026-05-12T02:30:00Z

En el ejemplo principal, el intervalo es siete por 3600, es decir, 25 200 segundos. Los minutos y segundos no cambian porque la duración solicitada incluye solo horas enteras. La fecha puede cambiar al cruzar la medianoche, el límite entre meses o el límite entre años.

¿Qué debes hacer si se rechaza la entrada?

Usa el rechazo como paso de diagnóstico. Resuelve la falta de información o la precisión no compatible antes de volver a intentarlo.

  • Solo tienes una fecha: Averigua la hora de publicación prevista y su desplazamiento. Una fecha civil por sí sola no permite identificar el instante inicial.
  • La marca de tiempo no tiene desplazamiento: Confirma si representa UTC o la hora local antes de añadir un sufijo.
  • La marca de tiempo tiene un desplazamiento distinto de cero: Convierte primero el instante representado a UTC. Cambiar solo el sufijo alteraría su significado.
  • Hay más de seis dígitos fraccionarios: Usa una herramienta que conserve esa precisión o define una política de redondeo explícita antes de usar este flujo de trabajo.
  • Las horas son negativas o fraccionarias: Introduce un número entero no negativo. Este programa está diseñado para restar horas enteras.
  • Los campos de calendario no son válidos: Corrige el valor de origen. Se rechazan fechas imposibles, como el 30 de febrero.

Python admite los años del 1 al 9999 en datetime; las restas que salgan de ese intervalo fallan. Su modelo de datetime también rechaza un campo de segundos de 60, aunque RFC 3339 permite ese valor para un segundo intercalar bajo determinadas condiciones. Límites de datetime de Python, RFC 3339, restricciones

Si lo que necesitas en realidad es «la misma hora local del reloj del día anterior», usa un flujo de trabajo de calendario con una zona con nombre. Las zonas con nombre pueden cambiar de desplazamiento durante las transiciones al horario de verano, así que esa tarea puede diferir de restar 24 horas transcurridas. La documentación de zoneinfo de Python muestra operaciones aritméticas a través de esas transiciones. Compatibilidad de zonas horarias IANA en Python

Para una marca de tiempo de publicación que ya esté expresada en UTC, céntrate en la operación: valida la entrada, resta la duración en horas enteras y conserva el sufijo UTC explícito en el valor que copies. Comprueba el cambio de fecha y la precisión fraccionaria antes de usar el resultado.

Fuentes