Analisando a sequência de datas no Go

138

Tentei analisar a sequência de datas "2014-09-12T11:45:26.371Z"no Go.

Código

layout := "2014-09-12T11:45:26.371Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout , str)

Eu recebi este erro:

tempo de análise "2014-11-12T11: 47: 39.489Z": mês fora do intervalo

Como posso analisar essa sequência de datas?

kannanrbk
fonte
Para futuros leitores, eu escrevi alguns exercícios para praticar data de análise github.com/soniah/date_practice
Sonia Hamilton
Seu layout deve ser exatamente 2006-01-02T15:04:05.000Zdevido a alguns padrões malucos
tharinduwijewardane 17/03

Respostas:

165

Use os números exatos do layout descritos aqui e um bom post aqui .

tão:

layout := "2006-01-02T15:04:05.000Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout, str)

if err != nil {
    fmt.Println(err)
}
fmt.Println(t)

dá:

>> 2014-11-12 11:45:26.371 +0000 UTC

Eu sei. Incompreensível. Também me pegou pela primeira vez. Go simplesmente não usa uma sintaxe abstrata para componentes datetime ( YYYY-MM-DD), mas esses números exatos ( acho que a hora do primeiro commit de ir Não, de acordo com isso . Alguém sabe?).

RickyA
fonte
118
Números de layout? O que? Por quê? Argh!
Darth Egregious
29
O que eles estavam pensando ! ? ou fumar?
Jishnu Prathap 01/03
14
Eu poderia ser um pouco tarde com os comentários aqui, mas não tenha medo de layout com números, basta usar constantes e seu código seria limpo :) por exemplo time.RFC3339
Davyd Dzhahaiev
11
Para aqueles que não obtêm os números de layout, admito que é muito estranho à primeira vista, mas depois que você se acostuma, acho que faz pelo menos tanto sentido quanto os dispositivos de layout típicos ('Eu uso "D", "d", "dd", "DD", etc?) e provavelmente mais sentido. Você só precisa saber sobre isso primeiro.
Threeve 5/02
5
É para fins mnemônicos, ou seja, você apenas precisa lembrar 1, 2, 3, 4, 5, 6, 7 dessas letras. Há um ótimo artigo discutindo isso: medium.com/@simplyianm/…
amigcamel
86

O layout para utilização é de fato " 2006-01-02T15:04:05.000Z" descrito no RickyA 's resposta .
Não é "a hora do primeiro commit de ir", mas uma maneira mnemônica de lembrar o layout.
Veja pkg / time :

O tempo de referência usado nos layouts é:

Mon Jan 2 15:04:05 MST 2006

que é hora do Unix 1136239445.
Como o MST é GMT-0700, o tempo de referência pode ser considerado como

 01/02 03:04:05PM '06 -0700

(1,2,3,4,5,6,7, desde que você lembre-se de que 1 é para o mês e 2 para o dia, o que não é fácil para um europeu como eu, usado para o formato de dia do mês)

Conforme ilustrado em " time.parse: por que golang analisa o tempo incorretamente? ", Esse layout (usando 1,2,3,4,5,6,7) deve ser respeitado exatamente .

VonC
fonte
Sim, isso também pega australianos! O MM / DD simplesmente não calcula para mim e eu tenho que continuar olhando para ele.
Simon Whitehead
3
@SimonWhitehead Eu concordo. Pelo menos, uma vez pesquisada, sei o que AA, MM, DD, hh, mm, ss representam e posso reordená-las facilmente. Com o Go, mesmo depois de pesquisar, preciso lembrar o que 1, 2, 3, 4 ... representam.
VonC 15/09/14
1
Da maneira que me lembro, é: Etapa 1) A ordenação de data "adequada" é ano> mês> dia> hora> minuto> segundo> etc. (porque o end-misto seria apenas sensorialmente arbitrário e inconsistente e para datas grandes endian é preferível a little-endian porque é favorável à classificação.) Isso nos daria 1 (ano), 2 (mês), 3 (dia), [...] Etapa 2) Go / Google é americano e os americanos colocam seus ano no final de suas datas; portanto, é 1 (mês), 2 (dia), [...], n (ano) Etapa 3) O fuso horário vai atrás de tudo o mais, porque os fusos horários são uma camada de abstração adicional.
Mtraceur
@mtraceur Sim ... Eu também sinto falta de web.archive.org/web/20180501100155/http://… (de github.com/bdotdub/fuckinggodateformat ). Quero dizer, strftimeFTW.
VonC 18/11/19
58

Como respondido, mas para salvar a digitação "2006-01-02T15:04:05.000Z"do layout, você pode usar o RFC3339 constante do pacote .

str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(time.RFC3339, str)

if err != nil {
    fmt.Println(err)
}
fmt.Println(t)

https://play.golang.org/p/Dgu2ZvHwTh

robstarbuck
fonte
1
Além disso, se você observar as constantes do pacote (vinculadas na resposta acima), existem vários outros formatos comuns fornecidos que podem ser usados. Se você precisar de algo um pouco diferente, use-os como ponto de partida.
Hugh
Esta e várias respostas recomendam 2006-01-02T15:04:05.000Ze mencionam que os Go's time.RFC3339também funcionariam. Mas time.RFC3339 = "2006-01-02T15:04:05Z07:00". Esses dois formatos são exatamente equivalentes na medida em que time.Parsee o que time.ParseInLocationfará?
Miles
1
Isso é @Miles direito, este teste confirma play.golang.org/p/T3dW1kTeAHl
robstarbuck
24

Vou sugerir o uso de time.RFC3339 constante do pacote de tempo. Você pode verificar outras constantes do pacote de horário. https://golang.org/pkg/time/#pkg-constants

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Time parsing");
    dateString := "2014-11-12T11:45:26.371Z"
    time1, err := time.Parse(time.RFC3339,dateString);
    if err!=nil {
    fmt.Println("Error while parsing date :", err);
    }
    fmt.Println(time1); 
}
Nishant Rawat
fonte
Você queria usar ponto e vírgula?
ChristoKiwi 12/03
20

Isso é muito tarde para a festa, e realmente não estou dizendo nada que já não tenha sido dito de uma forma ou de outra, principalmente através dos links acima, mas eu queria dar uma recapitulação TL; DR para aqueles com menos atenção:

A data e hora da sequência de formatação é muito importante. É como o Go sabe qual campo é qual. Eles geralmente são de 1 a 9 da esquerda para a direita, da seguinte maneira:

  • Janeiro / janeiro / janeiro / jan / 01 / _1 (etc) são para o mês
  • 02 / _2 são para o dia do mês
  • 15/03 / _3 / PM / P / pm / p são para hora e meridiano (15:00)
  • 04 / _4 são por minutos
  • 05 / _5 são por segundos
  • 2006/06 são para o ano
  • -0700 / 07:00 / MST são para o fuso horário
  • .999999999 / .000000000 etc são por segundos parciais (acho que a distinção é se zeros à direita forem removidos)
  • Seg / Segunda é o dia da semana (que 01-02-2006 era na verdade),

Portanto, não escreva "01-05-15" como formato de data, a menos que queira "Mês-Segunda-Hora"

(... novamente, este foi basicamente um resumo acima).

Loren Osborn
fonte
5

Isso pode ser muito tarde, mas é para pessoas que podem encontrar esse problema e podem querer usar um pacote externo para analisar a sequência de datas.

Eu tentei procurar por bibliotecas e encontrei esta:

https://github.com/araddon/dateparse

Exemplo do README:

package main

import (
    "flag"
    "fmt"
    "time"

    "github.com/apcera/termtables"
    "github.com/araddon/dateparse"
)

var examples = []string{
    "May 8, 2009 5:57:51 PM",
    "Mon Jan  2 15:04:05 2006",
    "Mon Jan  2 15:04:05 MST 2006",
    "Mon Jan 02 15:04:05 -0700 2006",
    "Monday, 02-Jan-06 15:04:05 MST",
    "Mon, 02 Jan 2006 15:04:05 MST",
    "Tue, 11 Jul 2017 16:28:13 +0200 (CEST)",
    "Mon, 02 Jan 2006 15:04:05 -0700",
    "Thu, 4 Jan 2018 17:53:36 +0000",
    "Mon Aug 10 15:44:11 UTC+0100 2015",
    "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)",
    "12 Feb 2006, 19:17",
    "12 Feb 2006 19:17",
    "03 February 2013",
    "2013-Feb-03",
    //   mm/dd/yy
    "3/31/2014",
    "03/31/2014",
    "08/21/71",
    "8/1/71",
    "4/8/2014 22:05",
    "04/08/2014 22:05",
    "4/8/14 22:05",
    "04/2/2014 03:00:51",
    "8/8/1965 12:00:00 AM",
    "8/8/1965 01:00:01 PM",
    "8/8/1965 01:00 PM",
    "8/8/1965 1:00 PM",
    "8/8/1965 12:00 AM",
    "4/02/2014 03:00:51",
    "03/19/2012 10:11:59",
    "03/19/2012 10:11:59.3186369",
    // yyyy/mm/dd
    "2014/3/31",
    "2014/03/31",
    "2014/4/8 22:05",
    "2014/04/08 22:05",
    "2014/04/2 03:00:51",
    "2014/4/02 03:00:51",
    "2012/03/19 10:11:59",
    "2012/03/19 10:11:59.3186369",
    // Chinese
    "2014年04月08日",
    //   yyyy-mm-ddThh
    "2006-01-02T15:04:05+0000",
    "2009-08-12T22:15:09-07:00",
    "2009-08-12T22:15:09",
    "2009-08-12T22:15:09Z",
    //   yyyy-mm-dd hh:mm:ss
    "2014-04-26 17:24:37.3186369",
    "2012-08-03 18:31:59.257000000",
    "2014-04-26 17:24:37.123",
    "2013-04-01 22:43",
    "2013-04-01 22:43:22",
    "2014-12-16 06:20:00 UTC",
    "2014-12-16 06:20:00 GMT",
    "2014-04-26 05:24:37 PM",
    "2014-04-26 13:13:43 +0800",
    "2014-04-26 13:13:44 +09:00",
    "2012-08-03 18:31:59.257000000 +0000 UTC",
    "2015-09-30 18:48:56.35272715 +0000 UTC",
    "2015-02-18 00:12:00 +0000 GMT",
    "2015-02-18 00:12:00 +0000 UTC",
    "2017-07-19 03:21:51+00:00",
    "2014-04-26",
    "2014-04",
    "2014",
    "2014-05-11 08:20:13,787",
    // mm.dd.yy
    "3.31.2014",
    "03.31.2014",
    "08.21.71",
    //  yyyymmdd and similar
    "20140601",
    // unix seconds, ms
    "1332151919",
    "1384216367189",
}

var (
    timezone = ""
)

func main() {
    flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone")
    flag.Parse()

    if timezone != "" {
        // NOTE:  This is very, very important to understand
        // time-parsing in go
        loc, err := time.LoadLocation(timezone)
        if err != nil {
            panic(err.Error())
        }
        time.Local = loc
    }

    table := termtables.CreateTable()

    table.AddHeaders("Input", "Parsed, and Output as %v")
    for _, dateExample := range examples {
        t, err := dateparse.ParseLocal(dateExample)
        if err != nil {
            panic(err.Error())
        }
        table.AddRow(dateExample, fmt.Sprintf("%v", t))
    }
    fmt.Println(table.Render())
}
stevenferrer
fonte
2
Infelizmente, há uma ambiguidade na ordem do dia por mês. O formato de data europeu fornece o dia primeiro e o mês o segundo, e o formato da hora nos EUA usa o inverso. Uma data como 5/3/2004 é ambígua. A data é válida no formato americano e europeu, mas 3 e 5 podem corresponder a dia e mês ou o inverso. dateParse assume o formato dos EUA.
chmike
-1

Se você trabalhou com a formatação / análise de data / hora em outros idiomas, pode ter notado que os outros idiomas usam espaços reservados especiais para a formatação de data / hora. Por exemplo, linguagem Ruby usa

%d for day
%Y for year

etc. Golang, em vez de usar códigos como os mencionados acima, usa espaços reservados de formato de data e hora que se parecem apenas com data e hora. Go usa o horário padrão, que é:

Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
or 
01/02 03:04:05PM '06 -0700

Então, se você perceber que o Go usa

01 for the day of the month,
02 for the month
03 for hours,
04 for minutes
05 for second
and so on

Portanto, por exemplo, para analisar 2020-01-29, a sequência de layout deve ser 06-01-02 ou 2006-01-02.

Você pode consultar a tabela de layout de espaço reservado completo neste link - https://golangbyexample.com/parse-time-in-golang/

user27111987
fonte