Introdução: O bug que todo desenvolvedor Go já enfrentou
\n\nVocê já viu a data 0001-01-01 00:00:00 +0000 UTC nos logs e pensou: "De onde isso veio? Eu não inicializei nada!"? Parabéns, você encontrou o zero value de time.Time em Go. Essa é uma armadilha clássica que gera milhares de visualizações no Stack Overflow e horas de debugging no mundo todo.
Neste artigo, vamos explorar o que é o zero value para time.Time, por que ele se comporta de forma inesperada, como diferenciar uma data "vazia" de uma real e, principalmente, como evitar esses problemas em produção. Se você programa em Go e trabalha com datas, este conteúdo vai te salvar de muita dor de cabeça.
\n\nO que é zero value em Go e por que time.Time é um caso especial
\n\nEm Go, cada tipo tem um valor zero (zero value). Para números, é 0; para strings, é ""; para ponteiros, é nil. A lógica é simples: se você declarou uma variável sem inicializá-la, ela recebe um valor "vazio". Mas com time.Time, a coisa é mais complicada.
O valor zero de time.Time não é o Unix timestamp 0 (1970-01-01), como seria de se esperar. É 0001-01-01 00:00:00 +0000 UTC. Por quê? Porque internamente, time.Time armazena nanossegundos desde 1º de janeiro do ano 1 (pelo calendário gregoriano). O zero nessa representação resulta no ano 1.
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\nJá percebeu o problema? Se você tentar verificar if t == 0 ou comparar com o Unix zero, seu código vai quebrar. Vamos analisar os principais erros com zero value time.Time e como evitá-los.
Top 5 erros com o valor zero de time.Time
\n\n1. Comparação com Unix timestamp 0
\n\nO erro mais comum é tentar verificar se o tempo está "vazio" comparando-o com time.Unix(0, 0). Isso não funciona, porque o valor zero não é o ano 1970.
// ❌ Erro: nunca será true\nvar t time.Time\nif t == time.Unix(0, 0) {\n fmt.Println("Tempo vazio")\n}\n\n// ✅ Correto: use o método IsZero()\nif t.IsZero() {\n fmt.Println("Tempo vazio")\n}\n\n\nO método IsZero() é sua principal ferramenta. Ele retorna true apenas para o valor zero, e não para qualquer data "antiga".
2. Serialização em JSON: null inesperado
\n\nAo serializar uma struct com time.Time para JSON, o valor zero se transforma na string "0001-01-01T00:00:00Z". Isso quebra APIs, frontends e bancos de dados. Os clientes veem uma data estranha, em vez de null.
type Event struct {\n Name string `json:"name"`\n StartTime time.Time `json:"start_time"`\n}\n\nfunc main() {\n e := Event{Name: "teste"}\n data, _ := json.Marshal(e)\n fmt.Println(string(data))\n // {"name":"teste","start_time":"0001-01-01T00:00:00Z"}\n // ❌ Deveria ser null ou o campo deveria estar ausente\n}\n\n\nSolução: use um ponteiro para time.Time (*time.Time) ou um tipo personalizado com lógica de serialização.
// ✅ Opção com ponteiro\ntype Event struct {\n Name string `json:"name"`\n StartTime *time.Time `json:"start_time,omitempty"`\n}\n\n// ✅ Ou tipo personalizado com 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\n3. Problemas com bancos de dados (SQL)
\n\nAo inserir um time.Time zero no PostgreSQL ou MySQL, você obterá a data 0001-01-01, o que causará um erro de restrição de intervalo (o ano 1 está fora do intervalo permitido).