Joakim Joakim -4 years ago 356
JSON Question

Unmarshal incorrectly formated datetime in Golang


I am learning Go and I'm trying to do some JSON unmarshaling of a datetime.

I have some JSON produced by a program I wrote in C, I am outputting what I thought was a valid ISO8601 / RFC3339 timezone offset. I'm using
with the following format string:


(Note that
is not supported by
natively, I have a wrapper that replaces it with the nanoseconds).

This will then produce the following result:


Unmarshaling this in Go however will not work:

package main

import (

func main() {
t, err := time.Parse(time.RFC3339Nano, "2016-08-08T21:35:14.052975+0200")
if err != nil {


panic: parsing time "2016-08-08T21:35:14.052975+0200" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "+0200" as "Z07:00"

(Working example:

This is because RFC3339 expects the timezone offset to be in the format
with a
, but
outputs it as

So I need to fix this in my C program to output the correct format.

%z The +hhmm or -hhmm numeric timezone (that is, the hour and
minute offset from UTC). (SU)


However, now I have a bunch of JSON files with this incorrect format:


instead of the correct (with the
in the timezone offset):


but I still want to be able to unmarshal it correctly in my Go program. Preferably two different JSON files with only this difference should parse in the exact same way.

Regarding marshaling back to JSON, the correct format should be used.

This is how I have defined it in my

Time time.Time `json:"time"`

So the question is, what is the "Go" way of doing this?

Also in my code example I am using
. How would I specify that in the metadata for the struct as well? As I have it now with just
will that ignore the nano seconds?

Answer Source

You can define your own time field type that supports both formats:

type MyTime struct {

func (self *MyTime) UnmarshalJSON(b []byte) (err error) {
    s := string(b)

    // Get rid of the quotes "" around the value.
    // A second option would be to include them
    // in the date format string instead, like so below: 
    //   time.Parse(`"`+time.RFC3339Nano+`"`, s) 
    s = s[1:len(s)-1]

    t, err := time.Parse(time.RFC3339Nano, s)
    if err != nil {
        t, err = time.Parse("2006-01-02T15:04:05.999999999Z0700", s)
    self.Time = t

type Test struct {
    Time MyTime `json:"time"`

Try on Go Playground

In the example above we take the predefined format time.RFC3339Nano, which is defined like this:

RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"

and remove the :


This time format used by time.Parse is described here:

Also see the documentation for time.Parse

P.S. The fact that the year 2006 is used in the time format strings is probably because the first version of Golang was released that year.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download