Time & Dates
Reviewed & published by Brayan K
The time package represents an instant as a time.Time and a span as a time.Duration, and its distinctive reference-layout (2006-01-02 15:04:05) drives all formatting and parsing.
Part of the free Go course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- Build times with time.Date and read fields
- Add durations and subtract two times
- Format with the 2006-01-02 reference layout
- Parse strings back into time.Time
- Shift by calendar units with AddDate
- Compare times with Before, After, Equal
1️⃣ Creating & Inspecting a Time
In real code you'd call time.Now(), but for reproducible examples we build a fixed instant with time.Date(year, month, day, hour, min, sec, nsec, loc). From a time.Time you can read every field — Year(), Month(), Day(), Weekday() — and get the Unix timestamp with Unix().
package main
import (
"fmt"
"time"
)
func main() {
// Use a FIXED time so output is deterministic.
// time.Date(year, month, day, hour, min, sec, nsec, loc).
t := time.Date(2026, time.June, 18, 14, 30, 0, 0, time.UTC)
fmt.Println("date:", t.Year(), t.Month(), t.Day())
fmt.Println("time:", t.Hour(), t.Minute())
fmt.Println("weekday:", t.Weekday())
// Unix timestamp (seconds since 1970-01-01 UTC).
fmt.Println("unix:", t.Unix())
}2️⃣ Durations & Comparing Times
A time.Duration is a length of time built from constants like time.Hour. Add one with t.Add(...), and subtract two times with later.Sub(t) to get the duration between them (convert with .Hours()). Compare instants with Before, After, and Equal; shift by calendar units (months, years) with AddDate.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2026, time.June, 18, 14, 30, 0, 0, time.UTC)
// Duration arithmetic: Add a duration, Sub two times.
later := t.Add(48*time.Hour + 30*time.Minute)
fmt.Println("48h30m later:", later.Format("2006-01-02 15:04"))
gap := later.Sub(t)
fmt.Println("gap hours:", gap.Hours()) // 48.5
// Compare times with Before / After / Equal.
fmt.Println("t before later?", t.Before(later)) // true
fmt.Println("equal to self?", t.Equal(t)) // true
// AddDate adjusts by calendar years/months/days.
nextYear := t.AddDate(1, 0, 0)
fmt.Println("next year:", nextYear.Year()) // 2027
}3️⃣ Formatting & Parsing with the Reference Layout
Go's signature feature: instead of letter codes, you describe a format by writing the reference date Mon Jan 2 15:04:05 MST 2006 the way you want the output to look. 2006 is the year, 01 the month, 02 the day, 15 the 24-hour clock, and so on. The same layout drives time.Parse, which reads a string back into a time.Time.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2026, time.June, 18, 14, 30, 45, 0, time.UTC)
// Go's layout uses the REFERENCE time Mon Jan 2 15:04:05 MST 2006.
// You spell out HOW you want it using that exact date's pieces.
fmt.Println(t.Format("2006-01-02")) // 2026-06-18
fmt.Println(t.Format("15:04:05")) // 14:30:45
fmt.Println(t.Format("Mon Jan 2, 2006")) // Thu Jun 18, 2026
fmt.Println(t.Format("3:04 PM")) // 2:30 PM
// Parse reads a string back into a time using the same layout.
parsed, err := time.Parse("2006-01-02", "2025-12-25")
fmt.Println(parsed.Format("Jan 2, 2006"), err)
// Sub measures the gap between two times as a Duration.
deadline := t.Add(3 * time.Hour)
fmt.Println("until deadline:", deadline.Sub(t)) // 3h0m0s
}🎯 Your Turn
Format the fixed time as 2026-07-04 09:05 using the reference layout. Fill in the blank.
package main
import (
"fmt"
"time"
)
func main() {
t := time.Date(2026, time.July, 4, 9, 5, 0, 0, time.UTC)
// Format t as "2026-07-04 09:05" using the REFERENCE layout.
// Remember: year=2006 month=01 day=02 hour=15 minute=04.
fmt.Println(t.Format("___")) // 👉 2006-01-02 15:04
// ✅ Expected output: 2026-07-04 09:05
}Common Errors (and the fix)
- ❌ Used "YYYY-MM-DD" as a layout — Go ignores letter codes. ✅ Use the reference date: "2006-01-02".
- ❌ Parse error "cannot parse" — your layout doesn't match the input. ✅ Make the layout describe the input string exactly.
- ❌ Compared times with == — surprising results from monotonic/location data. ✅ Use Equal.
- ❌ Added "a month" with Add(30 * 24 * time.Hour) — months vary in length. ✅ Use AddDate(0, 1, 0).
🎯 Mini-Challenge: Days Between Dates
Compute the number of days between two fixed dates: subtract to get a Duration, divide its Hours() by 24, and print with one decimal. Also print the end date as "Mon, 02 Jan 2006".
package main
import (
"fmt"
"time"
)
func main() {
// 🎯 MINI-CHALLENGE: how many days between two dates?
// 1) Sub(end, start) gives a Duration.
// 2) Divide its Hours() by 24 and print with one decimal: %.1f
// 3) Also print end formatted as "Mon, 02 Jan 2006".
//
// ✅ Expected output:
// days: 73.5
// end formatted: Sun, 15 Mar 2026
start := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC)
// your code here
}🎉 Lesson Complete!
- ✅ Build instants with time.Date(...); read fields like Year(), Weekday()
- ✅ Add a duration, Sub two times, AddDate by calendar units
- ✅ Format/parse with the reference layout 2006-01-02 15:04:05
- ✅ Compare with Before/After/Equal (not ==)
- ✅ time.Since and time.Sleep work with the live wall clock
Practice quiz
Which reference layout formats a date as 2026-07-04?
- YYYY-MM-DD
- 2020-12-31
- 2006-01-02
- 01-02-2006
Answer: 2006-01-02. Go uses the reference time Mon Jan 2 15:04:05 MST 2006 as the layout.
In the reference layout, what does 15 represent?
- The hour on a 24-hour clock
- The day of the month
- The minute
- The 12-hour hour
Answer: The hour on a 24-hour clock. 15 is the 24-hour clock; 04 is the minute, 05 the second.
Which constructor builds a fixed, deterministic instant?
- time.Now()
- time.Fixed(...)
- time.New(...)
- time.Date(year, month, day, hour, min, sec, nsec, loc)
Answer: time.Date(year, month, day, hour, min, sec, nsec, loc). time.Now() depends on the wall clock; time.Date gives reproducible output.
How do you get the duration between two times?
- later - earlier
- later.Sub(earlier)
- time.Diff(later, earlier)
- later.Minus(earlier)
Answer: later.Sub(earlier). Sub returns a time.Duration; later.Sub(t).Hours() converts it to hours.
Which shifts a time by calendar units like one year?
- t.AddDate(1, 0, 0)
- t.Add(1 * time.Year)
- t.AddYear(1)
- t.Add(365 * time.Hour)
Answer: t.AddDate(1, 0, 0). AddDate respects month lengths and leap years; there is no time.Year constant.
How should you test whether two times are the same instant?
- a == b
- a.Same(b)
- a.Equal(b)
- a.Compare(b) only
Answer: a.Equal(b). Use Equal; == can differ on monotonic-clock or location data.
What does t.Add(48*time.Hour + 30*time.Minute) add to t?
- 48 minutes and 30 seconds
- 48 hours and 30 minutes
- 78 minutes
- 48.5 minutes
Answer: 48 hours and 30 minutes. Duration constants combine: that is a 48h30m shift, i.e. 48.5 hours.
What does time.Parse use to read a string into a time.Time?
- A locale setting
- Automatic detection
- A regular expression
- The same reference layout you format with
Answer: The same reference layout you format with. Parse and Format share the 2006-01-02 style layout.
What does time.Since(t) return?
- The instant t formatted
- The elapsed duration since t (time.Now().Sub(t))
- A boolean for whether t is past
- The Unix timestamp of t
Answer: The elapsed duration since t (time.Now().Sub(t)). Since(t) is shorthand for time.Now().Sub(t).
What does t.Unix() return?
- Nanoseconds since midnight
- The weekday number
- Seconds since 1970-01-01 UTC
- Milliseconds since the program started
Answer: Seconds since 1970-01-01 UTC. Unix() is the Unix timestamp in seconds.
Continue this course
- Previous: Sorting (sort & slices.Sort)
- Next: Regular Expressions (regexp) — MustCompile, FindStringSubmatch capture groups, and ReplaceAllString
Frequently asked questions
Why does Go format dates with 2006-01-02 instead of yyyy-mm-dd?
Go uses a reference time — Mon Jan 2 15:04:05 MST 2006 — as the layout. You write the output you want using the pieces of that specific date: 2006 means the year, 01 the month, 02 the day, 15 the hour (24-hour), 04 the minute, 05 the second. It reads oddly at first, but it's unambiguous and you never have to memorize cryptic letter codes. A mnemonic: the numbers are 1 2 3 4 5 6 (month, day, hour, minute, second, year).
What is a time.Duration and how do I do arithmetic with it?
A time.Duration is a count of nanoseconds with handy constants like time.Hour and time.Minute. You add a duration to a time with t.Add(2 * time.Hour), and subtract two times with later.Sub(earlier) to get the duration between them. Methods like Hours(), Minutes(), and Seconds() convert a duration to a float64 in those units.
What's the difference between Add and AddDate?
Add takes a time.Duration and shifts by an exact amount of clock time, e.g. t.Add(48 * time.Hour). AddDate shifts by calendar units — years, months, and days — with t.AddDate(1, 0, 0) for one year. AddDate respects month lengths and leap years, so it's the right tool for 'one month from now' rather than adding a fixed number of hours.
How do I compare two times?
Use the methods Before, After, and Equal: a.Before(b), a.After(b), a.Equal(b). Avoid comparing time.Time values with == because two times can represent the same instant yet differ in their monotonic-clock reading or location; Equal compares the actual instant and handles those cases correctly.
What does time.Since do, and what about time.Sleep?
time.Since(t) is shorthand for time.Now().Sub(t) — the elapsed duration since t, which is great for timing how long an operation took. time.Sleep(d) pauses the current goroutine for the duration d, e.g. time.Sleep(2 * time.Second). Both deal with real wall-clock time, so their output isn't deterministic, which is why this lesson uses fixed time.Date values for the examples.