Parsing date string in Go

I tried parsing the date string "2014-09-12T11:45:26.371Z" in Go.

Code

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

I got this error:

parsing time "2014-11-12T11:47:39.489Z": month out of range

How can I parse this date string?


Solution 1:

Use the exact layout numbers described here and a nice blogpost here.

so:

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)

gives:

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

I know. Mind boggling. Also caught me first time. Go just doesn't use an abstract syntax for datetime components (YYYY-MM-DD), but these exact numbers (I think the time of the first commit of go Nope, according to this. Does anyone know?).

Solution 2:

The layout to use is indeed "2006-01-02T15:04:05.000Z" described in RickyA's answer.
It isn't "the time of the first commit of go", but rather a mnemonic way to remember said layout.
See pkg/time:

The reference time used in the layouts is:

Mon Jan 2 15:04:05 MST 2006

which is Unix time 1136239445.
Since MST is GMT-0700, the reference time can be thought of as

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

(1,2,3,4,5,6,7, provided you remember that 1 is for the month, and 2 for the day, which is not easy for an European like myself, used to the day-month date format)

As illustrated in "time.parse : why does golang parses the time incorrectly?", that layout (using 1,2,3,4,5,6,7) must be respected exactly.

Solution 3:

As answered but to save typing out "2006-01-02T15:04:05.000Z" for the layout, you could use the package's constant RFC3339.

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