Valor cero de time.Time en Go: trampas que matan tu código

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

Introducción: Ese error que todos hemos sufrido

\n\n

¿Alguna vez has recibido en los logs la fecha 0001-01-01 00:00:00 +0000 UTC y has pensado: «¿De dónde ha salido esto? ¡Si yo no lo he inicializado!»? Felicidades, te has encontrado con el valor cero de time.Time en Go. Es una trampa clásica que acumula miles de visitas en Stack Overflow y cientos de horas de depuración en todo el mundo.

\n\n

En este artículo analizaremos qué es el zero value para time.Time, por qué se comporta de forma inesperada, cómo distinguir una fecha «vacía» de una real y, sobre todo, cómo no pisar este rastrillo en producción. Si programas en Go y trabajas con fechas, este material te salvará de un tic nervioso.

\n\n

¿Qué es el zero value en Go y por qué time.Time es un caso especial?

\n\n

En Go, cada tipo tiene un valor cero (zero value). Para los números es 0, para las cadenas es "", para los punteros es nil. La lógica es simple: si declaras una variable sin inicializarla, obtiene un «vacío». Pero con time.Time es más complicado.

\n\n

El valor cero de time.Time no es el Unix timestamp 0 (1970-01-01), como cabría esperar. Es 0001-01-01 00:00:00 +0000 UTC. ¿Por qué? Porque internamente time.Time almacena nanosegundos desde el 1 de enero del año 1 (según el calendario gregoriano). El cero en esta representación da como resultado el año 1.

\n\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\nfunc main() {\n    var t time.Time\n    fmt.Println(t) // 0001-01-01 00:00:00 +0000 UTC\n    fmt.Println(t.Unix()) // -62135596800 (¡número negativo!)\n}\n
\n\n

¿Ya ves el problema? Si intentas comprobar if t == 0 o compararlo con el Unix cero, tu código se romperá. Analicemos los principales errores con zero value time.Time y cómo evitarlos.

\n\n

Top 5 errores con el valor cero de time.Time

\n\n

1. Comparación con Unix timestamp 0

\n\n

El error más común es intentar verificar si la hora está «vacía» comparándola con time.Unix(0, 0). Esto no funcionará porque el valor cero no es el año 1970.

\n\n
// ❌ Error: nunca será true\nvar t time.Time\nif t == time.Unix(0, 0) {\n    fmt.Println("La hora está vacía")\n}\n\n// ✅ Correcto: usa el método IsZero()\nif t.IsZero() {\n    fmt.Println("La hora está vacía")\n}\n
\n\n

El método IsZero() es tu herramienta principal. Devuelve true solo para el valor cero, no para cualquier fecha «temprana».

\n\n

2. Serialización en JSON: null inesperado

\n\n

Cuando serializas una estructura con time.Time a JSON, el valor cero se convierte en la cadena "0001-01-01T00:00:00Z". Esto rompe APIs, frontends y bases de datos. Los clientes ven una fecha extraña en lugar de null.

\n\n
type Event struct {\n    Name      string    `json:"name"`\n    StartTime time.Time `json:"start_time"`\n}\n\nfunc main() {\n    e := Event{Name: "test"}\n    data, _ := json.Marshal(e)\n    fmt.Println(string(data))\n    // {"name":"test","start_time":"0001-01-01T00:00:00Z"}\n    // ❌ Debería ser null o el campo debería estar ausente\n}\n
\n\n

Solución: usa un puntero a time.Time (*time.Time) o un tipo personalizado con lógica de serialización.

\n\n
// ✅ Opción con puntero\ntype Event struct {\n    Name      string     `json:"name"`\n    StartTime *time.Time `json:"start_time,omitempty"`\n}\n\n// ✅ O tipo personalizado con omitempty\ntype CustomTime struct {\n    time.Time\n}\n\nfunc (ct CustomTime) MarshalJSON() ([]byte, error) {\n    if ct.IsZero() {\n        return []byte("null"), nil\n    }\n    return json.Marshal(ct.Time)\n}\n
\n\n

3. Problemas con bases de datos (SQL)

\n\n

Al insertar un time.Time cero en PostgreSQL o MySQL obtendrás la fecha 0001-01-01, lo que provocará un error de restricción de rango (el año 1 está fuera del rango permitido).

Blogs

Book Recommendations