Zona horaria y errores de time.Parse
Un informe muestra la fecha de ayer para eventos que ocurrieron hoy, pero solo para usuarios en una zona horaria y solo después del horario de verano.
Busca en todas las páginas de la documentación
Un informe muestra la fecha de ayer para eventos que ocurrieron hoy, pero solo para usuarios en una zona horaria y solo después del horario de verano.
Esta página cubre las reglas de ubicación de time.Parse, el comportamiento del reloj monotónico, la serialización JSON y los pasos de depuración que exponen los defectos de tiempo sin adivinar.
Los valores time.Time representan un instante en la línea de tiempo más una ubicación opcional para mostrar.
Los errores de análisis (omitir la zona en el layout, mezclar local y UTC, ignorar el horario de verano) producen sutiles errores de "horas de diferencia" que las pruebas en una sola zona no detectan.
Las API JSON añaden otra capa: la serialización por defecto usa RFC3339 UTC, mientras que los clientes pueden interpretar las cadenas como hora local del reloj de pared.
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
// Analizar con zona explícita en el layout
t, err := time.Parse(time.RFC3339, "2026-07-15T09:00:00-07:00")
// Analizar hora local del reloj de pared en una zona específica
loc, _ := time.LoadLocation("America/Los_Angeles")
t, err := time.ParseInLocation("2006-01-02 15:04", "2026-07-15 09:00", loc)
// Almacenar/comparar en UTC, mostrar en la zona del usuario
utc := t.UTC()
display := utc.In(loc)Cuándo usar esto:
time.Now() con tiempos históricos analizadospackage main
import (
"encoding/json"
"fmt"
"time"
)
type Event struct {
At time.Time `json:"at"`
}
func main() {
// Análisis sin zona -> UTC
t1, _ := time.Parse("2006-01-02 15:04:05", "2026-07-15 09:00:00")
fmt.Println("analizado sin zona:", t1.Format(time.RFC3339), "loc", t1.Location())
loc, _ := time.LoadLocation("America/New_York")
t2, _ := time.ParseInLocation("2006-01-02 15:04:05", "2026-07-15 09:00:00", loc)
fmt.Println("analizado NY: ", t2.Format(time.RFC3339), "loc", t2.Location())
fmt.Println("¿instante igual?", t1.Equal(t2))
b, _ := json.Marshal(Event{At: t2})
fmt.Println("json:", string(b))
}Lo que esto demuestra:
time.Parse sin zona en la cadena de layout asigna UTC para entradas sin zonaEqual compara instantes; la salida de Format depende de la ubicaciónZ para UTCMon Jan 2 15:04:05 MST 2006 → usa el estilo 2006-01-02 en los layoutstime.Parse usa UTC cuando el layout no tiene zona; ParseInLocation establece la zona deseadatime.Time puede incluir una lectura monotónica para Sub/Since; se elimina con Format y JSONtime.Now() devuelve la zona local del entorno a menos que llames a UTC()| Entrada | Error típico | Solución |
|---|---|---|
Solo fecha "2026-07-15" | Analizado como medianoche UTC | Documenta el contrato; usa time.Date con zona |
| RFC3339 con compensación | OK si el layout incluye compensación | Usa la constante time.RFC3339 |
| Número de milisegundos Unix | Instante independiente de la zona | Prefiere para API que cruzan zonas |
Valor cero de time.Time | JSON "0001-01-01T00:00:00Z" | Usa un puntero o omite el vacío |
// Compara instantes, no cadenas formateadas
if !a.UTC().Equal(b.UTC()) { /* momento diferente */ }
// Trunca al día del calendario en una zona
day := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)"2006-01-02 15:04:05" se convierte en UTC, no local. Solución: ParseInLocation o exigir compensación en la entrada.Format - Las cadenas difieren para el mismo instante en diferentes zonas. Solución: Equal o comparar Unix UTC.time.Now().Location() es UTC en contenedores - Las imágenes sin TZ pueden usar UTC; las portátiles usan local. Solución: establecer TZ o siempre UTC() en servidores.LoadLocation falla en distroless sin el paquete tzdata. Solución: incrustar la importación _ "time/tzdata".Sub con tiempos de diferentes fuentes - Mezcla de tiempos monotónicos y solo de reloj de pared en Sub. Solución: usar t.UTC() antes de la aritmética entre tiempos analizados y de reloj.
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Almacenar segundos/milisegundos Unix en JSON | API globales, clientes simples | Los humanos leen JSON crudo con frecuencia |
Cadenas time.RFC3339 | Interoperabilidad HTTP/JSON estándar | Se necesita solo fecha sin hora |
Tipos de fecha civil (terceros) | Programación de calendario sin zona | Ya se usa time.Time en todas partes |
| Siempre UTC en la base de datos | Consistencia de informes | Las reglas de facturación de medianoche local necesitan una tabla de zonas |
MarshalJSON en time.Time emite UTC RFC3339.
El instante se conserva; la zona de visualización se pierde a menos que añadas un campo separado.
Usa los componentes de tiempo de referencia: año 2006, mes 01, día 02, hora 15, minuto 04, segundo 05, zona MST o -0700.
Copia constantes como time.RFC3339 cuando coincidan con la entrada.
No para layouts sin zona; se usa UTC.
Solo ParseInLocation o las compensaciones en la cadena establecen la zona.
Una lectura interna para medir duraciones inmune a saltos del reloj de pared.
No aparece en la salida formateada y se elimina al serializar.
Registra t.Format(time.RFC3339), t.Location() y t.UTC().Format(time.RFC3339).
Verifica si la entrada carecía de compensación y se analizó como UTC.
Las imágenes mínimas carecen de archivos de zona horaria.
Importa _ "time/tzdata" o instala tzdata en la imagen.
Almacena y compara en UTC; convierte a la zona del usuario en el límite de la interfaz de usuario.
Documenta el contrato de la API si los clientes envían horas locales.
Los controladores escanean en time.Time con la ubicación a menudo UTC.
Escanear en string pierde la seguridad de tipos; prefiere time.Time y zona explícita al escribir.
time.Parse("2006-01-02", "2026-07-15") es medianoche UTC.
Las reglas de facturación de "día local" necesitan ParseInLocation con la zona comercial.
Add usa duración absoluta en la línea de tiempo.
La aritmética de días del calendario necesita AddDate en la ubicación de destino.
timestamppb almacena el instante UTC.
Convierte con AsTime() y .In(loc) para mostrar.
Prueba de tabla con time.FixedZone y compensaciones conocidas.
Establece TZ en la matriz de CI o usa LoadLocation con tzdata incrustado.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado de Green Tea GC, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026