Menu

time em Golang: Now, Sleep, Format, Parse e durações

Como trabalhar com datas e horas em Go: time.Now e time.Sleep, aritmética com Duration, o layout de referência 2006-01-02 15:04:05 para Format e Parse, fusos horários, timestamps Unix, timers e tickers.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

O básico em um programa

time.Now() devolve o horário local atual, time.Sleep pausa a goroutine atual, time.Since mede o tempo decorrido e time.Date monta um momento específico. O resto da página trata de cada peça. Os exemplos usam datas fixas e UTC para que a saída seja a mesma onde quer que você os execute.

Sleep e Duration

Um time.Duration é um int64 que conta nanossegundos. O pacote define constantes para montar valores legíveis:

ConstanteValor
time.Nanosecond1
time.Microsecond1000 ns
time.Millisecond1000 µs
time.Second1000 ms
time.Minute60 s
time.Hour60 min

Não existe time.Day, porque um dia nem sempre tem 24 horas quando um fuso horário muda por causa do horário de verão. Use AddDate para dias de calendário (veja abaixo).

Dois bugs comuns vêm de o Duration ser um inteiro:

  • time.Sleep(5) dorme 5 nanossegundos. Sempre multiplique por uma unidade: time.Sleep(5 * time.Second).
  • time.Sleep(n * time.Second) não compila quando n é uma variável int. Converta: time.Duration(n) * time.Second. Uma constante como 5 funciona sem conversão porque constantes não tipadas se adaptam ao tipo Duration.

ParseDuration aceita ns, us (ou µs), ms, s, m e h, combinados como "2h45m" ou "1.5s". Ele não tem unidade para dias.

Formatação: o layout de referência 2006-01-02

O Go não usa %Y-%m-%d nem yyyy-MM-dd. Um layout é o horário de referência

Mon Jan 2 15:04:05 MST 2006

escrito do jeito que você quer que a saída fique. Os valores foram escolhidos para que cada um seja único: mês 1, dia 2, hora 3 (ou 15), minuto 4, segundo 5, ano 6 (2006), deslocamento de fuso -7 (-0700). Leia como 01/02 03:04:05PM '06 -0700.

Os tokens de layout de que você mais vai precisar:

TokenSignificadoExemplo
2006 / 06ano, 4 ou 2 dígitos2026 / 26
01 / 1 / Jan / Januarymês03 / 3 / Mar / March
02 / 2 / _2dia do mês (com zero, simples, com espaço)05 / 5 / " 5"
Mon / Mondaydia da semanaThu / Thursday
15hora, relógio de 24 horas09
03 / 3hora, relógio de 12 horas09 / 9
04 / 4minuto07 / 7
05 / 5segundo03 / 3
PM / pmmarcador AM ou PMAM
.000 / .999frações de segundo (fixas / sem zeros à direita).250 / .25
MSTabreviação do fusoUTC
-0700 / -07:00deslocamento numérico do fuso+0000 / +00:00
Z07:00como -07:00, mas imprime Z para UTCZ

Layouts predefinidos:

ConstanteLayout
time.RFC33392006-01-02T15:04:05Z07:00 (use este para APIs e JSON)
time.RFC3339Nano2006-01-02T15:04:05.999999999Z07:00
time.DateTime (Go 1.20)2006-01-02 15:04:05
time.DateOnly (Go 1.20)2006-01-02
time.TimeOnly (Go 1.20)15:04:05
time.Kitchen3:04PM
time.RFC1123Mon, 02 Jan 2006 15:04:05 MST (datas HTTP usam http.TimeFormat)

O erro clássico é escrever um layout com os números errados, por exemplo "2023-01-01". O Go não o rejeita. Ele copia os caracteres que não reconhece e substitui os que reconhece: cada 2 é o dia, 3 é a hora no relógio de 12 horas e os dois 01 são o mês, então 5 de março às 9:07 fica formatado como 5059-03-03. Um layout como "YYYY-MM-DD" não contém nenhum token e imprime a si mesmo sem mudança. Se as datas formatadas parecerem estranhas, confira se o layout usa exatamente os valores de referência.

Convertendo strings em horários

time.Parse(layout, value) usa os mesmos layouts e devolve um erro que você precisa verificar:

Sem fuso na entrada, o Parse devolve UTC. A mesma string de horário pode significar instantes diferentes dependendo do fuso, e é por isso que existe o ParseInLocation. A mensagem de erro nomeia a parte que não casou, o que ajuda quando você está depurando um layout.

Fusos horários

Um time.Time é um instante mais uma localização usada na exibição. Mudar a localização com In muda como ele é impresso, não qual momento ele é.

  • time.UTC está sempre disponível. Guarde e transmita horários em UTC (ou em RFC 3339 com deslocamento) e converta só para exibir.
  • time.Local é o fuso da máquina. Em servidores e containers muitas vezes é UTC, e em um notebook não é, então o código que depende dele se comporta de forma diferente em cada lugar.
  • time.LoadLocation("Europe/Berlin") lê o banco de dados IANA do sistema operacional. Imagens de container mínimas muitas vezes não o têm, e aí a chamada devolve um erro. O import em branco _ "time/tzdata" embute o banco no seu binário (cerca de 450 KB) para que sempre funcione. Sempre trate o erro.
  • time.FixedZone(name, offsetSeconds) cria um fuso com deslocamento constante. Ele não tem regras de horário de verão, então use-o para deslocamentos que você recebeu, não para regiões com nome.

Aritmética e comparação

O que reparar na saída:

  • AddDate(0, 1, 0) em 31 de janeiro dá 3 de março, não 28 de fevereiro. O Go soma um mês, chega a "31 de fevereiro" e depois normaliza o excesso. Se você precisa de "mesmo dia do mês seguinte, limitado ao fim do mês", escreva essa lógica você mesmo.
  • Sub devolve um Duration, que chega no máximo a cerca de 292 anos. Para diferenças em dias de calendário, compare as datas à meia-noite UTC e divida por 24 horas.
  • Para pegar o início do dia, remonte o horário a partir de Date(). t.Truncate(24 * time.Hour) arredonda em relação ao tempo zero em UTC, então dá a resposta errada para qualquer fuso diferente de UTC.

Compare com Equal, Before e After, nunca com ==. time.Now() inclui uma leitura do relógio monotônico, usada para que time.Since continue correto se o relógio de parede for ajustado. O == compara essa leitura e também a localização, então dois valores Time do mesmo instante podem ser diferentes. Pelo mesmo motivo, não use time.Time como chave de map sem normalizá-lo antes (t.UTC().Round(0) remove a leitura monotônica).

O time.Time zero é 1º de janeiro do ano 1, 00:00 UTC. Verifique-o com t.IsZero().

Medindo o tempo decorrido

start := time.Now()
doWork()
log.Printf("doWork took %v", time.Since(start))

time.Since(start) é time.Now().Sub(start), e time.Until(deadline) é deadline.Sub(time.Now()). Os dois usam o relógio monotônico quando disponível, então ficam imunes a mudanças no relógio do sistema. Para fazer benchmark de código, use o suporte a benchmarks do pacote testing em vez de medir à mão.

Timers e tickers

time.After(d) devolve um channel que recebe uma vez depois de d. Um time.Timer é a mesma coisa com um método Stop. Um time.Ticker entrega um valor a cada período até você pará-lo.

Os três ticks em 20, 40 e 60 ms chegam bem antes do timer de 110 ms, então o programa para depois do terceiro tick. time.AfterFunc(d, f) executa f na sua própria goroutine depois de d, o que é prático para trabalhos atrasados avulsos.

Desde o Go 1.23, timers e tickers que não são mais referenciados são recolhidos pelo coletor de lixo mesmo que você nunca chame Stop, e o channel de um timer parado ou reiniciado não entrega mais um valor velho. Chamar Stop com defer continua sendo a forma clara de dizer que a vida do ticker acabou. Quando um limite de tempo vale para uma operação inteira, e não para uma única espera, um context.WithTimeout costuma ficar mais legível que um timer.

Horários em JSON

time.Time é convertido para e de strings RFC 3339 no JSON automaticamente, com precisão de nanossegundos:

type Event struct {
	Name string    `json:"name"`
	At   time.Time `json:"at"`
}
// {"name":"deploy","at":"2026-09-23T14:30:00Z"}

Uma string JSON em outro formato falha no unmarshal. Para timestamps Unix ou formatos próprios, guarde um int64 ou uma string e converta, ou defina um tipo com o seu próprio UnmarshalJSON.

Erros comuns

  • time.Sleep(1) ou time.Sleep(n) com um número puro. São nanossegundos.
  • Layouts com os dígitos errados. "2023-01-01" ou "YYYY-MM-DD" não são layouts. Use "2006-01-02".
  • Confundir minutos e meses. Minutos são 04, meses são 01. "15:01" imprime a hora e depois o mês, não o minuto.
  • Comparar com ==. Use Equal.
  • Depender de time.Local. Ele muda de máquina para máquina. Seja explícito com time.UTC ou com uma localização carregada.
  • Ignorar o erro de LoadLocation ou Parse. Os dois falham com entradas reais. Um Parse que falhou devolve o horário zero, que é impresso como ano 1, e um LoadLocation que falhou devolve uma localização nil que faz t.In(loc) causar panic.

Perguntas frequentes

Como fazer sleep em Go?

Chame time.Sleep com um time.Duration: time.Sleep(2 * time.Second) ou time.Sleep(500 * time.Millisecond). Um número puro como time.Sleep(2) compila, mas dorme 2 nanossegundos, porque um Duration conta nanossegundos. O Sleep só bloqueia a goroutine atual.

Por que o Go usa 2006-01-02 15:04:05 para formatos de data?

O Go formata datas por exemplo. O layout é o horário de referência Mon Jan 2 15:04:05 MST 2006 escrito do jeito que você quer que a saída fique. As partes dele sobem em sequência na ordem americana: mês 1, dia 2, hora 3 (15 no relógio de 24 horas), minuto 4, segundo 5, ano 6 (2006), deslocamento de fuso 7 (-0700). Então "2006-01-02" significa ano-mês-dia e "02/01/2006" significa dia/mês/ano.

Como converter uma string de data em Go?

Use time.Parse(layout, value) com um layout escrito no horário de referência: t, err := time.Parse("2006-01-02", "2026-09-23"). Sempre verifique o err. Sem informação de fuso na string, o resultado fica em UTC; use time.ParseInLocation para interpretá-la em outro fuso.

Como obter um timestamp Unix em Go?

time.Now().Unix() devolve os segundos desde 1º de janeiro de 1970 UTC como um int64. UnixMilli(), UnixMicro() e UnixNano() dão unidades menores. Para o caminho inverso, use time.Unix(sec, 0) ou time.UnixMilli(ms).

Como comparar dois horários em Go?

Use t1.Before(t2), t1.After(t2) e t1.Equal(t2). Não use ==: ele também compara a localização e a leitura do relógio monotônico, então dois valores do mesmo instante podem ser diferentes. t2.Sub(t1) dá a diferença como um Duration.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR