Golang Time Format: Date, Time, RFC3339, Parse, and Layout Examples

Format and parse time in Go using the reference layout 2006-01-02 15:04:05, time.Now().Format, RFC3339, Z07:00 for UTC as Z, Parse and ParseInLocation, common mistakes with YYYY-MM-DD, and copy-paste layout tables.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Golang Time Format: Date, Time, RFC3339, Parse, and Layout Examples

Format turns a time.Time into a string; Parse and ParseInLocation do the reverse. Both use the same idea: the layout is not YYYY-MM-DD—it is spelled with Go’s reference instant so the string you write looks like the string you want out. For clocks, durations, and time.Now without formatting detail, start with Golang time basics.

Tested on: Go 1.22 on 64-bit Linux; snippets were run with go run while this article was revised.


Quick answer: use the reference date, not YYYY-MM-DD

Call t.Format(layout). For a calendar date like 2026-06-18, the usual layout is 2006-01-02 (year 2006, month 01, day 02). For a full stamp, combine pieces from the reference time Mon Jan 2 15:04:05 MST 2006.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.Date(2026, 6, 18, 14, 30, 0, 0, time.UTC)
	fmt.Println(t.Format("2006-01-02"))
	fmt.Println(t.Format("2006-01-02 15:04:05"))
	fmt.Println(t.Format(time.RFC3339))
}
Output

You should see 2026-06-18, a space-separated date and time on that date, and an RFC3339 string with a Z or offset.


How time formatting works in Go

Go uses a reference time, not YYYY-MM-DD tokens

Other ecosystems often use pattern letters (YYYY, MM). Go instead writes an example timestamp: if you want 2026-06-18, you literally write 2006-01-02 because those digits are the reference calendar date January 2, 2006. Anything in the layout that is not a layout word is copied unchanged (punctuation, literal words).

The reference time: Mon Jan 2 15:04:05 MST 2006

Memorize the components you need most:

Piece in reference Role in output
2006 Four-digit year
01 Month (numeric)
02 Day of month
15 Hour, 24-hour clock
03 Hour, 12-hour clock
04 Minute
05 Second
PM AM or PM marker

Important: 01 is the month and 04 is the minute—easy to swap by mistake.


Format current time in Go

Format time.Now as date and time

Use separate calls when you need a stable log line versus a full timestamp; both use the same reference digits in the layout string.

Format current time in UTC

UTC() shifts the instant before formatting so the suffix uses Z or a predictable offset.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println(time.Now().Format("2006-01-02"))
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
	fmt.Println(time.Now().UTC().Format(time.RFC3339))
}
Output

The first two lines follow your local zone; the UTC line ends with Z or an offset depending on the instant.


Common Go time format layouts

Date-only layouts

These layouts omit clock fields entirely. For example, t.Format("2006-01-02") prints only the calendar part for t’s location (same digits as in the table below).

Time-only layouts

These layouts omit the calendar portion; combine them with date layouts when you need both. Examples: t.Format("15:04:05") for 24-hour clock, or t.Format("03:04 PM") for 12-hour with an AM/PM marker.

Date and time layouts

Use a space or T separator to mirror how your downstream system expects the string. Examples: t.Format("2006-01-02 15:04:05") or t.Format("2006-01-02T15:04:05Z07:00") when the suffix must follow RFC-style zone rules.

RFC3339 and ISO-like layouts

Prefer time.RFC3339 or time.RFC3339Nano when you exchange timestamps with APIs; they already encode offset rules. Example: t.UTC().Format(time.RFC3339) for a Z or offset suffix without hand-writing the full layout string.

Desired shape Layout or constant
2026-06-18 2006-01-02
18-06-2026 02-01-2006
18/06/2026 02/01/2006
Jun 18, 2026 Jan 2, 2006
June 18, 2026 January 2, 2006
14:30:00 15:04:05
14:30 15:04
02:30 PM 03:04 PM
2026-06-18 14:30:00 2006-01-02 15:04:05
2026-06-18T14:30:00Z time.RFC3339 or 2006-01-02T15:04:05Z07:00
2026-06-18T14:30:00.123Z 2006-01-02T15:04:05.000Z07:00 or time.RFC3339Nano
20260618143000 20060102150405
Thu, 18 Jun 2026 14:30:00 UTC Mon, 02 Jan 2006 15:04:05 MST

Parse time from string in Go

The layout for Parse must mirror the input string exactly, including separators and field order. time.Parse uses UTC when the layout has no zone. When the text has no offset but is wall time in a city, use time.ParseInLocation with time.LoadLocation or a fixed zone.

Use time.Parse with matching layout

time.Parse(layout, value) returns an error when punctuation, field width, or order differs from the layout string. Example: time.Parse("02/01/2006", "18/06/2026") succeeds because the slashes and day/month/year order match the layout.

Parse date-only strings

A layout like 2006-01-02 only reads the calendar portion; the resulting Time is midnight in UTC unless you follow up with In or ParseInLocation. Example: time.Parse("2006-01-02", "2026-06-18") yields 2026-06-18 00:00:00 +0000 UTC.

Parse RFC3339 timestamps

time.RFC3339 matches strings with a T separator and a zone (Z or ±hh:mm); use RFC3339Nano when fractional seconds appear. Example: time.Parse(time.RFC3339, "2026-06-18T14:30:00Z") reads the instant in UTC.

Use time.ParseInLocation for local time

When the input has no zone suffix but represents local wall time (for example a form field in Asia/Kolkata), parse with ParseInLocation and a loaded *time.Location. Example: time.ParseInLocation("2006-01-02 15:04:05", "2026-06-18 09:00:00", loc) with loc from time.LoadLocation("Asia/Kolkata") or time.FixedZone(...).

go
package main

import (
	"fmt"
	"time"
)

func main() {
	layout := "2006-01-02"
	t, err := time.Parse(layout, "2026-06-18")
	if err != nil {
		panic(err)
	}
	fmt.Println(t.UTC())

	rfc := "2026-06-18T14:30:00Z"
	t2, err := time.Parse(time.RFC3339, rfc)
	if err != nil {
		panic(err)
	}
	fmt.Println(t2)

	loc := time.FixedZone("IST", 5*3600+30*60)
	t3, err := time.ParseInLocation("2006-01-02 15:04:05", "2026-06-18 09:00:00", loc)
	if err != nil {
		panic(err)
	}
	fmt.Println(t3)
}
Output

You get a midnight UTC parse for the date-only string, the RFC3339 instant in UTC, and the wall time interpreted in the fixed IST offset.


Format and parse time zones

Layout fragment Meaning Example
MST Zone abbreviation UTC, IST
-0700 Offset, no colon +0530
-07:00 Offset with colon +05:30
Z0700 Z if UTC else compact offset Z or +0530
Z07:00 Z if UTC else offset with colon Z or +05:30

Z07:00 is what people mean when they search for RFC-style output: UTC prints as Z, other locations print a signed offset. Combine with the rest of the layout, for example 2006-01-02T15:04:05Z07:00.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	ist := time.FixedZone("IST", 5*3600+30*60)
	t := time.Date(2026, 6, 18, 12, 0, 0, 0, ist)
	fmt.Println(t.Format("2006-01-02T15:04:05Z07:00"))
	fmt.Println(t.UTC().Format("2006-01-02T15:04:05Z07:00"))
}
Output

The first line shows a +05:30 style suffix; the second shows Z for the same instant in UTC.


Go layout symbols explained

Meaning Layout token
Four-digit year 2006
Two-digit year 06
Numeric month 01
Short month name Jan
Long month name January
Day of month (zero-padded) 02
Day without leading zero 2
Short weekday Mon
Long weekday Monday
24-hour hour 15
12-hour hour 03
Minute 04
Second 05
AM / PM PM
Zone name MST
Numeric offset (colon) -07:00
UTC as Z or offset Z07:00
Fractional seconds (milliseconds) .000
Fractional seconds (trimmed) .999

Common mistakes with Go time format

Using YYYY-MM-DD instead of 2006-01-02

Letters that are not part of the reference vocabulary are emitted literally, so "YYYY-MM-DD" prints those letters, not the date.

go
package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.Date(2026, 6, 18, 0, 0, 0, 0, time.UTC)
	fmt.Println(t.Format("YYYY-MM-DD"))
	fmt.Println(t.Format("2006-01-02"))
}
Output

The first line is the literal YYYY-MM-DD; the second is the real calendar date.

Using 04 for month or 01 for minute

01 is always month and 04 is always minute in layouts.

Layout does not match the input string

go
package main

import (
	"fmt"
	"time"
)

func main() {
	_, err := time.Parse("2006-01-02", "18-06-2026")
	fmt.Println(err)
}
Output

Parse returns an error because the hyphens and field order do not match; switch the layout to 02-01-2006 for that input.

Confusing UTC, local time, and offset

Use UTC(), Local(), and ParseInLocation deliberately. Store UTC in systems; render local time at the edge.

Rebuilding timestamps with fmt instead of Format

Prefer Format so zone, padding, and fractional seconds stay consistent.


Go time format cheat sheet

Goal Pattern
Date only time.Now().Format("2006-01-02")
Date and time time.Now().Format("2006-01-02 15:04:05")
UTC API stamp time.Now().UTC().Format(time.RFC3339)
RFC3339 with nanos t.Format(time.RFC3339Nano)
ISO-style with Z rule "2006-01-02T15:04:05Z07:00"
Parse date time.Parse("2006-01-02", value)
Parse with zone time.ParseInLocation(layout, value, loc)

Which layout should you use?

  • Interchange and JSON-style APIs: time.RFC3339 or RFC3339Nano.
  • Human logs in one time zone: 2006-01-02 15:04:05 plus an explicit zone policy.
  • Filename-safe: 20060102150405.

Summary

Go time format and golang time parse both revolve around the reference time: build layouts from 2006-01-02 15:04:05 and friends, never from YYYY-MM-DD. Use t.Format for output, time.Parse when UTC is correct for zoneless strings, and ParseInLocation for regional wall time. Z07:00 gives RFC-style Z in UTC and numeric offsets elsewhere. Match layouts to inputs byte-for-byte, remember 01 is month and 04 is minute, and lean on named constants like time.RFC3339 when they fit your contract.


References


Frequently Asked Questions

1. How do I format time in Go?

Call t.Format with a layout string built from the reference time Mon Jan 2 15:04:05 MST 2006, for example t.Format("2006-01-02").

2. How do I format current time in Go?

Use time.Now().Format(layout), for example time.Now().Format("2006-01-02 15:04:05").

3. How do I format date only in Go?

Use a date-only layout such as "2006-01-02" or "Jan 2, 2006".

4. Why does Go use 2006-01-02 for date formatting?

The digits are the reference date January 2, 2006 written in order year-month-day; the layout string mirrors the output shape.

5. Why does YYYY-MM-DD not work in Go?

Go does not treat YYYY or MM as special tokens; unknown letters are copied literally, so use 2006-01-02 instead.

6. How do I parse time from string in Go?

Use time.Parse(layout, value) with the same layout shape as the input, or time.ParseInLocation when the text has no zone but is wall time in a region.

7. What is RFC3339 format in Go?

Use the constant time.RFC3339 for strings like 2006-01-02T15:04:05Z07:00.

8. What does Z07:00 mean in Go time format?

It prints Z for UTC and a numeric offset with a colon for non-UTC, matching ISO-style timestamps.

9. What is the layout format in Go time?

The layout is an example timestamp using the reference time; each component picks how that field is formatted or parsed.

10. Why does time.Parse fail in Go?

The input must match the layout exactly, including punctuation and field order; wrong zones or missing ParseInLocation also cause errors.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …