RFC 3339 en Go: 5 errores al parsear fechas y cómo solucionarlos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Parseo de RFC 3339 / ISO-8601 en Go: por qué incluso desarrolladores experimentados tropiezan

\n\n

¿Alguna vez has escrito en Go algo como time.Parse("2006-01-02T15:04:05Z", input), recibiste un error y te sentiste como si el lenguaje se estuviera burlando de ti a propósito? Te suena. El parseo de fechas y horas es uno de esos temas donde, aparentemente todo es simple, pero en la práctica acechan muchas trampas.

\n\n

En Stack Overflow, la pregunta "Parsing RFC-3339 / ISO-8601 date-time string in Go" ha acumulado miles de visitas. La gente se confunde con los formatos, olvida los nanosegundos, sufre con las zonas horarias y se enfada con el número «mágico» 2006-01-02T15:04:05Z. En este artículo analizaremos los 5 errores más comunes y mostraremos cómo evitarlos de una vez por todas. ¡Allá vamos!

\n\n

Un poco de teoría: ¿qué son RFC 3339 e ISO 8601?

\n\n

Antes de sumergirnos en el código, aclaremos rápidamente los términos. ISO 8601 es el estándar internacional para la representación de fecha y hora. RFC 3339 es una versión «recortada» del mismo, popular en la web (por ejemplo, en JSON, API, logs).

\n\n

Las cadenas típicas de RFC 3339 se ven así:

\n\n
2025-01-15T10:30:00Z\n2025-01-15T10:30:00+03:00\n2025-01-15T10:30:00.123456789Z
\n\n

En Go, para el parseo se usa la función time.Parse(layout, value). Y aquí es donde empieza lo interesante.

\n\n

Error n.º 1: Layout (plantilla) incorrecto — la principal causa de dolor de cabeza

\n\n

Go utiliza un enfoque único: el formato no se define con códigos como YYYY-MM-DD, sino con una fecha concreta: Mon Jan 2 15:04:05 MST 2006. Es fácil de recordar: 01/02 03:04:05PM '06 -0700 (mes, día, hora, minuto, segundo, año, zona horaria).

\n\n

Los principiantes a menudo intentan escribir algo como:

\n\n
// ❌ ¡Error!\nt, err := time.Parse("YYYY-MM-DDTHH:MM:SSZ", "2025-01-15T10:30:00Z")
\n\n

Go simplemente no entenderá ese formato. El layout correcto para RFC 3339 es time.RFC3339:

\n\n
// ✅ Correcto\nt, err := time.Parse(time.RFC3339, "2025-01-15T10:30:00Z")\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Println(t) // 2025-01-15 10:30:00 +0000 UTC
\n\n

La constante time.RFC3339 es igual a la cadena "2006-01-02T15:04:05Z07:00". Observa Z07:00 — es la notación de la zona horaria.

\n\n

Error n.º 2: Ignorar los nanosegundos (time.RFC3339 vs time.RFC3339Nano)

\n\n

El time.RFC3339 estándar no admite nanosegundos. Si tu cadena contiene una parte fraccionaria de segundo:

\n\n
2025-01-15T10:30:00.123456789Z
\n\n

…entonces el parseo con time.RFC3339 devolverá un error:

\n\n
// ❌ Error: parsing time "2025-01-15T10:30:00.123456789Z" as "2006-01-02T15:04:05Z07:00": cannot parse ".123456789Z" as "Z07:00"\nt, err := time.Parse(time.RFC3339, "2025-01-15T10:30:00.123456789Z")
\n\n

La solución es usar time.RFC3339Nano:

\n\n
// ✅ Correcto\nt, err := time.Parse(time.RFC3339Nano, "2025-01-15T10:30:00.123456789Z")\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Println(t) // 2025-01-15 10:30:00.123456789 +0000 UTC
\n\n

Consejo: Si no estás seguro de si habrá nanosegundos, usa time.RFC3339Nano — es compatible hacia atrás y funcionará para ambos casos.

\n\n

Error n.º 3: Zona horaria — ¿Z o +00:00 no son lo mismo?

\n\n

Las cadenas 2025-01-15T10:30:00Z y 2025-01-15T10:30:00+00:00 significan lo mismo (UTC), pero Go puede procesarlas de manera diferente si el layout se especifica incorrectamente.

\n\n
// ✅ Ambas variantes funcionan con time.RFC3339\nt1, _ := time.Parse(time.RFC3339, "2025-01-15T10:30:00Z")\nt2, _ := time.Parse(time.RFC3339, "2025-01-15T10:30:00+00:00")\nfmt.Println(t1.Equal(t2)) // true
\n\n

Pero si escribes tu propio layout, ten cuidado:

\n\n
    \

Blogs

Book Recommendations