Fechas y horas en Go

El paquete time de Go tiene una peculiaridad que desconcierta a todo el mundo la primera vez: el formato de las fechas no se escribe con letras tipo dd/mm/yyyy, sino con una fecha de ejemplo concreta. Una vez entendido eso, el resto es sencillo.

Crear una fecha

ahora := time.Now()
fija := time.Date(2026, time.October, 5, 18, 30, 0, 0, time.UTC)

fmt.Println(fija)
salida2026-10-05 18:30:00 +0000 UTC

Los argumentos de time.Date van de mayor a menor: año, mes, día, hora, minuto, segundo, nanosegundos y zona. El mes no es un número suelto sino un valor con nombre, time.October, lo que evita el clásico error de contar los meses desde cero.

El formato: la plantilla es una fecha

Aquí está la rareza. En lugar de %Y-%m-%d o dd/MM/yyyy, Go pide que escribas cómo quedaría una fecha concreta: la del 2 de enero de 2006 a las 15:04:05.

fmt.Println(fija.Format("2006-01-02"))
fmt.Println(fija.Format("02/01/2006 15:04"))
fmt.Println(fija.Format(time.RFC3339))
salida2026-10-05
05/10/2026 18:30
2026-10-05T18:30:00Z
Por qué esa fecha y no otra. Porque sus componentes van en orden: 1 mes, 2 día, 3 hora, 4 minuto, 5 segundo, 6 año, 7 huso. Es decir, 01/02 03:04:05 PM ’06 -0700. Una vez lo ves, se recuerda. Y si no, los formatos más usados ya están como constantes: time.RFC3339, time.DateOnly, time.TimeOnly.

Leer una fecha de un texto

t, err := time.Parse("2006-01-02", "2026-12-25")
fmt.Println(t.Format("02/01/2006"), err)
salida25/12/2026 <nil>

El primer argumento vuelve a ser la plantilla, y tiene que describir exactamente el texto que llega. Si no coincide, el error lo dice con bastante claridad:

salidaparsing time "25/12/2026" as "2006-01-02": cannot parse "25/12/2026" as "2006"

Sumar y restar

fmt.Println(fija.Add(90 * time.Minute).Format("15:04"))
fmt.Println(fija.AddDate(0, 2, 0).Format("2006-01-02"))
salida20:00
2026-12-05

Son dos métodos distintos a propósito. Add trabaja con duraciones fijas —minutos, horas— y AddDate con años, meses y días, que no duran siempre lo mismo. Sumar «un mes» a un 31 de enero no es sumar 30 días, y por eso no se hace con Add.

Diferencias entre fechas

navidad := time.Date(2026, time.December, 25, 0, 0, 0, 0, time.UTC)

d := navidad.Sub(fija)
fmt.Printf("faltan %.0f días (%v)\n", d.Hours()/24, d.Round(time.Hour))
fmt.Println("¿es anterior?", fija.Before(navidad))
salidafaltan 80 días (1926h0m0s)
¿es anterior? true

Sub devuelve un time.Duration, que se imprime en horas y minutos y del que se puede sacar lo que quieras con .Hours(), .Minutes() o .Seconds(). Para comparar están Before, After y Equal.

No compares fechas con ==. Dos time.Time pueden representar el mismo instante y no ser iguales como estructuras, porque llevan dentro la zona y un reloj monótono. Para eso está Equal.

Husos horarios

madrid, err := time.LoadLocation("Europe/Madrid")
if err != nil {
	return err
}
fmt.Println("UTC   :", fija.Format("15:04 MST"))
fmt.Println("Madrid:", fija.In(madrid).Format("15:04 MST"))
salidaUTC   : 18:30 UTC
Madrid: 20:30 CEST

In no cambia el instante, cambia cómo se mira. Fíjate en que salió CEST y no CET: el paquete sabe que en octubre todavía rige el horario de verano.

Medir cuánto tarda algo

inicio := time.Now()
hacerAlgo()
fmt.Println("tardó", time.Since(inicio).Round(10*time.Millisecond))
salidatardó 120ms

time.Since(inicio) es la forma corta de time.Now().Sub(inicio), y el Round del final evita que salgan catorce decimales. Para medir rendimiento de verdad, con repeticiones y estadísticas, lo adecuado es go test -bench.

Lo que más se usa

Para Usa
Ahora time.Now()
Una fecha concreta time.Date(...)
Pasar a texto t.Format("2006-01-02")
Leer de un texto time.Parse(plantilla, texto)
Sumar horas o minutos t.Add(2 * time.Hour)
Sumar días o meses t.AddDate(0, 1, 0)
Diferencia b.Sub(a)
Comparar a.Before(b), a.Equal(b)
Cambiar de huso t.In(loc)
Cronometrar time.Since(inicio)

Todo el código se compiló y ejecutó con Go 1.25 antes de publicarla; las salidas están copiadas de esa ejecución, incluido el error de formato. Documentación oficial: paquete time.