Analizando cadena de fecha en Ir

138

Intenté analizar la cadena de fecha "2014-09-12T11:45:26.371Z"en Ir.

Código

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

Tengo este error:

tiempo de análisis "2014-11-12T11: 47: 39.489Z": mes fuera de rango

¿Cómo puedo analizar esta cadena de fecha?

kannanrbk
fuente
Para futuros lectores, escribí algunos ejercicios para practicar el análisis de fechas github.com/soniah/date_practice
Sonia Hamilton
Su diseño debería 2006-01-02T15:04:05.000Zdeberse a algún estándar loco
tharinduwijewardane

Respuestas:

165

Utilice los números de diseño exactos descritos aquí y una buena publicación de blog aquí .

entonces:

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)

da:

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

Lo sé. Mente alucinante. También me atrapó por primera vez. Ir simplemente no usa una sintaxis abstracta para los componentes de fecha y hora ( YYYY-MM-DD), sino estos números exactos ( creo que la hora de la primera confirmación de ir No, de acuerdo con esto . ¿Alguien sabe?).

RickyA
fuente
118
Números de diseño? ¿Qué? ¿Por qué? Argh!
Darth Egregious
29
Que estaban pensando ! ? o fumando?
Jishnu Prathap
14
Puede que llegue un poco tarde con los comentarios aquí, pero no tenga miedo del diseño con números, solo use constantes y su código estará limpio :) por ejemplo, tiempo.RFC3339
Davyd Dzhahaiev
11
Para aquellos que no obtienen los números de diseño, admito que es muy extraño a primera vista, pero una vez que te acostumbras, creo que tiene al menos tanto sentido como los dispositivos de diseño típicos ('¿Uso "D", "d", "dd", "DD", etc?), y probablemente más sentido. Solo tienes que saberlo primero.
tres
55
Es para fines mnemotécnicos, es decir, solo debes recordar 1, 2, 3, 4, 5, 6, 7 estas letras. Hay un gran artículo discutiendo esto: medium.com/@simplyianm/…
amigcamel
86

El diseño a usar " 2006-01-02T15:04:05.000Z" se describe en la respuesta de RickyA . No es "el momento del primer commit de go", sino más bien una forma mnemónica de recordar dicho diseño. Ver paquete / hora :

El tiempo de referencia utilizado en los diseños es:

Mon Jan 2 15:04:05 MST 2006

que es tiempo de Unix 1136239445.
Como MST es GMT-0700, el tiempo de referencia puede considerarse como

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

(1,2,3,4,5,6,7, siempre que recuerde que 1 es para el mes y 2 para el día, que no es fácil para un europeo como yo, acostumbrado al formato de fecha día-mes)

Como se ilustra en " time.parse: ¿por qué Golang analiza el tiempo incorrectamente? ", Ese diseño (usando 1,2,3,4,5,6,7) debe respetarse exactamente .

VonC
fuente
¡Sí, eso también atrapa a los australianos! MM / DD simplemente no computa para mí y tengo que seguir mirándolo.
Simon Whitehead
3
@SimonWhitehead Estoy de acuerdo. Al menos, una vez que lo busco, sé lo que significan AA, MM, DD, hh, mm, ss y puedo reordenarlos fácilmente. Con Go, incluso después de buscarlo, necesito recordar qué significan 1, 2, 3, 4 ...
VonC
1
La forma en que lo recuerdo es: Paso 1) El orden de fecha "correcto" es año> mes> día> hora> minuto> segundo> etc. (Debido a que el endian mixto sería no sensiblemente arbitrario e inconsistente y para fechas grandes- endian es preferible a little-endian porque es amigable.) Esto nos daría 1 (año), 2 (mes), 3 (día), [...] Paso 2) Ir / Google son estadounidenses y los estadounidenses ponen su año al final de sus fechas, por lo que es 1 (mes), 2 (día), [...], n (año) Paso 3) La zona horaria va detrás de todo lo demás porque las zonas horarias son una capa de abstracción adicional.
mtraceur
@mtraceur Sí ... yo también extraño web.archive.org/web/20180501100155/http://… (de github.com/bdotdub/fuckinggodateformat ). Quiero decir, strftimeFTW.
VonC
58

Como se respondió, pero para guardar la escritura "2006-01-02T15:04:05.000Z"para el diseño, puede usar la constante RFC3339 del paquete .

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
fuente
1
Además, si observa las constantes del paquete (vinculadas en la respuesta anterior), existen otros formatos comunes que se pueden usar. Si necesita algo ligeramente diferente, úselos como punto de partida.
Hugh
Esta y varias respuestas recomiendan 2006-01-02T15:04:05.000Zy mencionan que Go time.RFC3339también funcionaría. Pero time.RFC3339 = "2006-01-02T15:04:05Z07:00". ¿Son estos dos formatos exactamente equivalentes en cuanto a qué time.Parsey qué time.ParseInLocationhará?
Miles
1
Así es @Miles, esta prueba lo confirma play.golang.org/p/T3dW1kTeAHl
robstarbuck
24

Sugeriré usar time.RFC3339 constante del paquete de tiempo. Puede consultar otras constantes desde el paquete de tiempo. 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
fuente
¿Querías usar punto y coma?
ChristoKiwi
20

Esto es bastante tarde para la fiesta, y realmente no digo nada que no se haya dicho ya de una forma u otra, principalmente a través de los enlaces anteriores, pero quería dar un TL; resumen de DR a aquellos con menos capacidad de atención:

La fecha y hora de la cadena de formato go es muy importante. Así es como Go sabe qué campo es cuál. Generalmente son 1-9 de izquierda a derecha de la siguiente manera:

  • Enero / enero / enero / enero / 01 / _1 (etc.) son por mes
  • 02 / _2 son para el día del mes
  • 15/03 / _3 / PM / P / pm / p son para hora y meridiano (3pm)
  • 04 / _4 son por minutos
  • 05 / _5 son por segundos
  • 2006/06 son para el año
  • -0700 / 07:00 / MST son para zona horaria
  • .999999999 / .000000000 etc. son por segundos parciales (creo que la distinción es si se eliminan los ceros finales)
  • Lunes / lunes son días de la semana (que 01-02-2006 realmente era),

Por lo tanto, no escriba "01-05-15" como su formato de fecha, a menos que quiera "Mes-Segunda-Hora"

(... de nuevo, esto fue básicamente un resumen de lo anterior).

Loren Osborn
fuente
5

Esto puede ser muy tarde, pero esto es para las personas que pueden tropezar con este problema y pueden querer usar un paquete externo para analizar la cadena de fecha.

Intenté buscar bibliotecas y encontré esta:

https://github.com/araddon/dateparse

Ejemplo de 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
fuente
2
Desafortunadamente, existe una ambigüedad en el orden día mes. El formato de fecha europeo proporciona el primer día y el segundo mes, y el formato de hora de EE. UU. Usa el reverso. Una fecha como 3/5/2004 es ambigua. La fecha es válida en formato estadounidense y europeo, pero 3 y 5 pueden corresponder a día y mes o al revés. dateParse asume el formato de EE. UU.
chmike
-1

Si ha trabajado con el formato / análisis de hora / fecha en otros idiomas, es posible que haya notado que los otros idiomas usan marcadores de posición especiales para el formato de fecha / hora. Por ejemplo, usos del lenguaje ruby

%d for day
%Y for year

etc. Golang, en lugar de utilizar códigos como el anterior, utiliza marcadores de posición de formato de fecha y hora que solo parecen fecha y hora. Go usa el tiempo estándar, que es:

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

Entonces, si notas que 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

Por lo tanto, por ejemplo, para analizar 2020-01-29, la cadena de diseño debe ser 06-01-02 o 2006-01-02.

Puede consultar la tabla de diseño de marcador de posición completa en este enlace: https://golangbyexample.com/parse-time-in-golang/

usuario27111987
fuente