Comprueba las horas de calendario de IA antes de crear eventos
En esta página
Un asistente de IA convierte «el martes a las nueve en Nueva York» en una marca de tiempo para el calendario. Parece precisa, pero su desfase respecto a UTC puede corresponder al invierno y no al verano. Peor aún, la hora propuesta puede caer dentro de una franja que no existe cuando se adelantan los relojes.
Antes de crear eventos, comprueba que la hora local y el desfase propuestos concuerdan con una zona horaria confirmada por el usuario. Este tutorial de Python funciona sin conexión y rechaza marcas de tiempo incoherentes sin contactar con un calendario ni llamar a un modelo. Complementa la planificación semanal con IA, en lugar de confiar en que el plan se valide solo.
1. Define un contrato limitado para el evento
Usa Python 3.9 o posterior con datos de zonas horarias de IANA disponibles. La documentación de zoneinfo explica la búsqueda de datos del sistema y el uso alternativo del paquete oficial tzdata.
Exige una marca de tiempo con el formato exacto 2025-07-15T09:00:00-04:00: fecha completa, segundos y desfase numérico. Se excluyen deliberadamente abreviaturas, desfases ausentes, fracciones de segundo y Z; es un contrato pequeño para una aplicación, no un validador universal de ISO 8601. Valida la estructura JSON por separado con el comprobador estricto de JSON de IA.
Establece America/New_York a partir de preferencias revisadas por el usuario, no de una suposición del modelo. Conserva la petición original y la marca de tiempo propuesta para revisarlas. Los casos de prueba siguientes usan fechas históricas de 2025, no reservas reales.
2. Convierte a UTC y vuelve a la zona aprobada
Guarda lo siguiente como check_calendar.py en un directorio nuevo:
import re
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
ZONE = ZoneInfo("America/New_York")
SHAPE = (r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"
r"[+-](?:[01][0-9]|2[0-3]):[0-5][0-9]")
fixtures = [
("winter", "2025-01-15T09:00:00-05:00"),
("summer_wrong", "2025-07-15T09:00:00-05:00"),
("spring_gap", "2025-03-09T02:30:00-05:00"),
("fall_first", "2025-11-02T01:30:00-04:00"),
("fall_second", "2025-11-02T01:30:00-05:00"),
("no_offset", "2025-07-15T09:00:00"),
("bad_date", "2025-02-29T09:00:00-05:00"),
]
def check_stamp(value):
if not isinstance(value, str) or not re.fullmatch(SHAPE, value):
return "invalid format", None
try:
proposed = datetime.fromisoformat(value)
instant = proposed.astimezone(timezone.utc)
local = instant.astimezone(ZONE)
except (ValueError, OverflowError):
return "invalid datetime", None
if (local.replace(tzinfo=None) != proposed.replace(tzinfo=None)
or local.utcoffset() != proposed.utcoffset()):
return "zone mismatch", None
return "valid", instant
def main():
accepted = 0
for label, value in fixtures:
reason, instant = check_stamp(value)
suffix = " " + instant.isoformat() if instant is not None else ""
print(f"{label}: {reason}{suffix}")
accepted += reason == "valid"
print(f"accepted={accepted}/{len(fixtures)}")
return int(not fixtures or accepted != len(fixtures))
if __name__ == "__main__":
raise SystemExit(main())
La documentación de astimezone() describe una conversión que conserva el instante. Aquí, el desfase proporcionado determina un instante UTC; al convertirlo de vuelta, se consulta qué hora local y desfase correspondían realmente a la zona aprobada. Ambos deben coincidir con la propuesta. Comparar solo los instantes no detectaría una hora local mal etiquetada. El filtro de formato también limita las horas y los minutos del desfase para evitar normalizaciones permisivas del analizador.
No valides limitándote a asignar ZoneInfo mediante replace(tzinfo=...): PEP 495 explica las horas locales inexistentes y repetidas, y señala que los constructores no rechazan las horas del salto. Quitar tzinfo en el código anterior solo sirve para comparar los campos del reloj; no realiza una conversión.
3. Verifica los rechazos y los ejemplos corregidos
Ejecuta:
python3 check_calendar.py
Salida estándar esperada:
winter: valid 2025-01-15T14:00:00+00:00
summer_wrong: zone mismatch
spring_gap: zone mismatch
fall_first: valid 2025-11-02T05:30:00+00:00
fall_second: valid 2025-11-02T06:30:00+00:00
no_offset: invalid format
bad_date: invalid datetime
accepted=3/7
El comando termina con código 1 y sin salida de error: cuatro registros necesitan revisión. zone mismatch abarca deliberadamente tanto desfases incorrectos como horas locales inexistentes; no diagnostica qué corrección pretendía el usuario. Un lote vacío también falla.
Las dos marcas de tiempo de otoño pasan, pero representan instantes separados por una hora. Un desfase explícito resuelve mecánicamente la hora repetida; no demuestra que el usuario eligiera esa aparición. Comprueba esa diferencia y dos correcciones revisadas:
python3 - <<'PYTEST'
import check_calendar as demo
first = demo.check_stamp("2025-11-02T01:30:00-04:00")[1]
second = demo.check_stamp("2025-11-02T01:30:00-05:00")[1]
assert (second - first).total_seconds() == 3600
assert demo.check_stamp(None)[0] == "invalid format"
assert demo.check_stamp("2025-01-15T09:00:00-04:60")[0] == "invalid format"
assert demo.check_stamp("2025-01-15T09:00:00+00:00")[0] == "zone mismatch"
print("edge checks passed")
demo.fixtures = [
("summer_fixed", "2025-07-15T09:00:00-04:00"),
("spring_fixed", "2025-03-09T03:30:00-04:00"),
]
raise SystemExit(demo.main())
PYTEST
Salida estándar esperada:
edge checks passed
summer_fixed: valid 2025-07-15T13:00:00+00:00
spring_fixed: valid 2025-03-09T07:30:00+00:00
accepted=2/2
El comando termina con código 0 y sin salida de error. Ambos comandos se probaron localmente con Python 3.11 y los datos tzdata 2023c instalados. El segundo solo cambia los casos de prueba en memoria y no modifica el archivo guardado. Mover la cita de primavera a las 03:30 ilustra un cambio aprobado por el usuario, nunca una reparación automática.
4. Resuelve los problemas antes de permitir escrituras en el calendario
- Faltan datos de zona:
ZoneInfoNotFoundErroral iniciar significa que no se puede cargar la zona aprobada. Proporciona datos IANA del sistema o la dependenciatzdatadocumentada; no uses silenciosamente la zona del servidor. - Resultados distintos entre equipos: compara sus versiones de datos de zonas horarias. IANA actualiza la base de datos cuando los gobiernos cambian los desfases y las reglas de horario de verano. Registra la versión utilizada y actualízala antes de reservar fechas futuras.
- Incoherencia: confirma con el usuario la ciudad, la fecha y la hora local deseada. No intentes reparar todos los fallos cambiando el desfase.
- Marca válida, reunión equivocada: esto solo comprueba la coherencia, no la intención, disponibilidad de asistentes, duración, recurrencia ni permiso de escritura. Vuelve a validar cada repetición futura con las reglas correspondientes.
Usa una vista previa de solo lectura antes de conceder acceso al calendario, separando propuesta y acción igual que al revisar planes de renombrado de archivos de IA. Guarda juntos la marca local confirmada, el identificador de zona y el instante UTC para facilitar la auditoría.
Conclusión práctica
Exige un desfase explícito y una zona de confianza, y comprueba que concuerdan antes de crear el evento. Una marca de tiempo válida reduce el trabajo de revisión; nunca autoriza por sí sola la reserva.
Artículos relacionados
Comprueba las cifras de resúmenes de IA con una tabla de referencia
Compara versiones de prompts de IA con una prueba de regresión en Python
Revisa planes de renombrado de IA sin cambiar archivos
Comprueba citas textuales de IA con fuentes locales y Python
Evalúa la clasificación de incidencias con una matriz de confusión
Evalúa probabilidades de IA con la puntuación de Brier en Python
Detecta texto repetido entre entrenamiento y prueba antes de evaluar una IA
Comprueba los marcadores de traducciones de IA con Python
Rechaza JSON ambiguo de IA antes de automatizar con Python
Elige umbrales de revisión de IA con cobertura y tasas de error
Evalúa transcripciones de IA con la tasa de error por palabra
Prueba expresiones regulares de IA con casos pequeños en Python
Últimos artículos
Evalúa campos extraídos por IA con precisión y recall de coincidencia exacta
Comprueba las rutas propuestas por IA antes de escribir con Python
Evita actualizaciones de IA obsoletas con un control de versión en SQLite
Comprueba las dependencias de tareas de IA antes de programarlas con Python
Revisa los cambios JSON de la IA con una lista de campos permitidos
Combina resultados RAG con fusión de rangos recíprocos
Comprueba citas textuales de IA con fuentes locales y Python
Comprueba las cifras de resúmenes de IA con una tabla de referencia
Elige umbrales de revisión de IA con cobertura y tasas de error
Comprueba los marcadores de traducciones de IA con Python
Compara versiones de prompts de IA con una prueba de regresión en Python