Cannot parse string to time with timezone offset included RFC3339 with seemingly contradictory errors

Issue

I am using Golang and time.Time to Parse a given string into a time object.

Using RFC3339 and time.Parse here is an example of my code:

t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z07:00")
if err != nil {
   return nil, err
}

I get the follow errors.

When I include timezone offset I am getting:

ERRO[0002] parsing time "2020-08-08T00:22:44Z07:00": extra text: 07:00

When I don’t include the timezone offset I am getting:

ERRO[0002] parsing time "2020-08-08T00:15:36" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"

How do I avoid this issue when parsing time into a structured object?

Solution

The presence of the character Z in the Go time.RFC3339 constant "2006-01-02T15:04:05Z07:00" does not mean that a date conforming to the pattern is supposed to include a Z followed by the time zone offset.

In fact, a date with Z followed by anything else is not a valid RFC3339 date. Hence, your first error extra text: 07:00

The Z stands for "Zulu Time", i.e. UTC time zone. From the RFC3339 specs:

  Z           A suffix which, when applied to a time, denotes a UTC
              offset of 00:00; often spoken "Zulu" from the ICAO
              phonetic alphabet representation of the letter "Z".

So the Z alone is already providing the time zone information, that is, UTC.

As @Flimzy noted in the comments, 2020-08-08T00:22:44Z would be a valid RFC3339 date.

    t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z")
    if err != nil {
        panic(err)
    }
    fmt.Println(t) // 2020-08-08 00:22:44 +0000 UTC

Now, if you read the RFC3339 standard further, you see this definition:

time-zone       = "Z" / time-numoffset
time-numoffset  = ("+" / "-") time-hour [[":"] time-minute]

Which means that the time zone part of the date is either a Z or the offset. Clearly, since the Z already represents the offset 00:00, you can’t have one more +/-HH:mm offset in the same date string.

But this also means that Z or the +/-HH:mm must be present. So if you remove both of them, you get your second error: cannot parse "" as "Z07:00"

The parser is attempting to read the "2020-08-08T00:15:36" string as RFC3339 so it expects either a Z or an offset after the seconds (or milliseconds, if any).


In conclusion, the Z07:00 in the Go time.RFC3339 pattern is just a representation of the fact that the date string is supposed to include a time zone. A valid RFC3339 date string must include either Z or the offset.

Answered By – blackgreen

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.