Trabalho Avançado com Datas e Horas em Go: do parsing à otimização
\n\nNo desenvolvimento moderno em Go (Golang), o trabalho com datas e horas vai muito além da simples exibição da data atual. Em um nível avançado, o desenvolvedor precisa saber como fazer parsing eficiente de formatos complexos, trabalhar com fusos horários, gerenciar timers e canais, além de otimizar a performance. Neste artigo, abordaremos as técnicas essenciais que ajudarão você a escrever código Go robusto e rápido para trabalhar com dados temporais.
\n\n1. Parsing e formatação avançados de tempo
\n\nO pacote time em Go usa uma abordagem única: para formatação e parsing, é utilizada a data de referência Mon Jan 2 15:04:05 MST 2006. No entanto, na prática, frequentemente encontramos formatos não padronizados, como ISO 8601, RFC 3339 ou strings personalizadas.
Exemplo de parsing ISO 8601 com microssegundos:
\n\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n // ISO 8601 com nanossegundos\n input := "2024-03-15T14:30:45.123456789Z"\n layout := "2006-01-02T15:04:05.000000000Z"\n t, err := time.Parse(layout, input)\n if err != nil {\n panic(err)\n }\n fmt.Println(t) // 2024-03-15 14:30:45.123456789 +0000 UTC\n}\n\n\nFormatação considerando localidade e valores zero:
\n\nt := time.Now()\n// Formato com zeros à esquerda\nfmt.Println(t.Format("02.01.2006 15:04:05")) // 15.03.2024 14:30:45\n\n// Formato para logs com microssegundos\nfmt.Println(t.Format("2006-01-02T15:04:05.000000Z07:00"))\n\n\nDica: Para fazer parsing de formatos não padronizados, use time.Parse com um template exato. Se o formato for dinâmico, utilize time.ParseInLocation para especificar o fuso horário.
2. Trabalho com fusos horários e zonas de tempo
\n\nUm dos erros mais comuns é ignorar os fusos horários. Em Go, para trabalhar com zonas, usa-se time.Location. É importante lembrar que o banco de dados de fusos horários (IANA) deve estar disponível no servidor.
Exemplo de conversão entre zonas:
\n\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n // Hora atual em UTC\n now := time.Now().UTC()\n fmt.Println("UTC:", now)\n\n // Carregar o fuso horário de Moscou\n loc, err := time.LoadLocation("Europe/Moscow")\n if err != nil {\n panic(err)\n }\n\n // Converter para Moscow\n moscowTime := now.In(loc)\n fmt.Println("Moscow:", moscowTime)\n\n // Parsing com especificação explícita da zona\n input := "2024-03-15 14:30:45"\n layout := "2006-01-02 15:04:05"\n t, _ := time.ParseInLocation(layout, input, loc)\n fmt.Println("Parsed in Moscow:", t)\n}\n\n\nTratamento da mudança para horário de verão/inverno:
\n\n// Verificar se a hora é de transição\nt := time.Date(2024, 3, 31, 2, 30, 0, 0, loc)\n_, offset := t.Zone()\nfmt.Println("Offset:", offset/3600, "hours") // Pode ser 3 ou 4\n\n\nImportante: Evite usar time.FixedZone em código de produção, pois ele não considera o horário de verão (DST). Sempre use time.LoadLocation com o nome correto do IANA.
3. Timers, tickers e gerenciamento de tempo através de canais
\n\nO trabalho avançado com tempo inclui o gerenciamento de operações assíncronas. Go fornece ferramentas poderosas: time.Timer, time.Ticker e time.After.
Timer com cancelamento via contexto:
\n\npackage main\n\nimport (\n "context"\n "fmt"\n "time"\n)\n\nfunc main() {\n ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n defer cancel()\n\n timer := time.NewTimer(1 * time.Second)\n defer timer.Stop()\n\n select {\n case <-timer.C:\n fmt.Pr