How to parse a RFC3339 timestamp in Go

Avatar of the author Willem Schots
22 Dec, 2023
~2 min.

The RFC3339 standard is a popular way to format timestamps on the internet. RFC3339 timestamps:

  • Are human readable.
  • Represent instants in time. No intervals.
  • Are in UTC time or include an UTC offset. No local time.
  • Allow for different precision levels, from years to fractions of a second.
  • Use the YYYY-MM-DD format. No confusion between MM-DD-YYYY or DD-MM-YYYY formats.
  • Are string sortable when every timestamps use consistent time zone information and precision.

This makes it a very pragmatic format.

RFC3339 is a tailored version of the broader ISO8601 standard. It’s not entirely a subset, but it’s pretty close.

RFC3339 in Go’s time package

The Go time package includes two constants that that define appropriate reference layouts for RFC3339 timestamps:

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

If we pass these to the time.Parse function we can parse RFC3339 formatted timestamps into time.Time values.

However, not every valid RFC3339 timestamp can be parsed this way:

  • Go expects RFC3339 timestamps to always contain the capital T character, the standard allows for lower case or a space.
  • The standard allows for leap seconds, the time does not deal with them.
package main

import (

func main() {
	timestamps := []string{

	for i, ts := range timestamps {
		t, err := time.Parse(time.RFC3339, ts)
		if err != nil {
			log.Fatalf("%d: %v", i, err)


Subscribe to my Newsletter and Keep Learning.

Gain access to more content and get notified of the latest articles:

I send emails every 1-2 weeks and will keep your data safe. You can unsubscribe at any time.

Hello! I'm the Willem behind

I created this website to help new Go developers, I hope it brings you some value! :)

You can follow me on Twitter/X, LinkedIn or Mastodon.

Thanks for reading!