Getting the Current Time
time.Timetime.Time is a struct representing an instant in time with nanosecond precision. It includes wall clock, monotonic clock reading, and timezone location.
Current time — wall clock & monotonic
Basics
package main import ( "fmt" "time" ) func main() { now := time.Now() // wall + monotonic fmt.Println(now) // 2026-06-23 14:30:05.123456789 +0000 UTC m=+0.000000001 fmt.Println(now.Year()) // 2026 fmt.Println(now.Month()) // June fmt.Println(now.Day()) // 23 fmt.Println(now.Hour()) // 0-23: 14 fmt.Println(now.Minute()) // 0-59: 30 fmt.Println(now.Second()) // 0-59: 5 fmt.Println(now.Nanosecond()) // 0-999999999: 123456789 fmt.Println(now.Weekday()) // Tuesday fmt.Println(now.YearDay()) // 1-366: 174 }
Constructing a specific time
time.Date
// time.Date(year, month, day, hour, min, sec, nsec, loc) launch := time.Date(2026, time.July, 4, 9, 0, 0, 0, time.UTC) fmt.Println(launch) // Zero value — Jan 1, year 1, 00:00:00 UTC var zero time.Time fmt.Println(zero.IsZero()) // true
Output
2026-07-04 09:00:00 +0000 UTC true
Formatting & Parsing
Reference TimeGo uses a reference time as the format template —
Mon Jan 2 15:04:05 MST 2006. This is not a placeholder; use these exact values to define your layout.
Format — custom layouts
Format()
now := time.Now() // Common patterns fmt.Println(now.Format("2006-01-02")) fmt.Println(now.Format("02/01/2006")) fmt.Println(now.Format("Jan 2, 2006")) fmt.Println(now.Format("3:04 PM")) fmt.Println(now.Format("Mon, 02 Jan 2006 15:04:05 -0700")) // Pre-defined layouts in the time package fmt.Println(now.Format(time.RFC3339)) fmt.Println(now.Format(time.RFC822)) fmt.Println(now.Format(time.Kitchen))
Output
2026-06-23 23/06/2026 Jun 23, 2026 2:30 PM Tue, 23 Jun 2026 14:30:05 +0000 2026-06-23T14:30:05Z 23 Jun 26 14:30 UTC 2:30PM
Parsing — string → time.Time
time.Parse
// time.Parse(layout, value) — always UTC t1, err := time.Parse("2006-01-02", "2026-06-23") if err != nil { fmt.Println("error:", err) } fmt.Println(t1) // time.ParseInLocation — respects local timezone loc, _ := time.LoadLocation("America/New_York") t2, _ := time.ParseInLocation("2006-01-02 15:04:05", "2026-06-23 09:00:00", loc) fmt.Println(t2) // RFC3339 is the most portable internet format t3, _ := time.Parse(time.RFC3339, "2026-06-23T14:30:05Z") fmt.Println(t3.Format(time.RFC3339))
Output
2026-06-23 00:00:00 +0000 UTC 2026-06-23 09:00:00 -0400 EDT 2026-06-23T14:30:05Z
Durations
time.Durationtime.Duration is an int64 representing nanoseconds. All duration constants — time.Second, time.Minute, etc. — are just multiples of time.Nanosecond.
Duration constants
Literals
var ( ns = time.Nanosecond // 1 us = time.Microsecond // 1000 ms = time.Millisecond // 1_000_000 s = time.Second // 1e9 m = time.Minute // 60e9 h = time.Hour // 3600e9 ) d := 2*time.Hour + 30*time.Minute fmt.Println(d) // 2h30m0s
Duration from string
ParseDuration
d, _ := time.ParseDuration("1h30m") fmt.Println(d) // 1h30m0s d2, _ := time.ParseDuration("300ms") fmt.Println(d2) // 300ms d3, _ := time.ParseDuration("2h45m30s") fmt.Println(d3.Hours()) // 2.758... fmt.Println(d3.Minutes()) // 165.5 fmt.Println(d3.Seconds()) // 9930
Truncate & Round a duration
Precision
d := 17*time.Minute + 45*time.Second fmt.Println(d.Truncate(time.Minute)) // 17m0s (floor) fmt.Println(d.Round(time.Minute)) // 18m0s (nearest)
Time Arithmetic
Add · Sub · Since · Untilpast
t1
t1
now
t2
t2
future
t3
t3
Since(t1) = now − t1 ▶ Duration
Until(t3) = t3 − now ▶ Duration
Sub(t1) = t2 − t1 ▶ Duration
Add, Sub, Since, Until
Arithmetic
now := time.Now() // Add a duration to a time tomorrow := now.Add(24 * time.Hour) nextWeek := now.Add(7 * 24 * time.Hour) yesterday := now.Add(-24 * time.Hour) // AddDate(years, months, days) — calendar-aware nextMonth := now.AddDate(0, 1, 0) nextYear := now.AddDate(1, 0, 0) // Sub: time.Time − time.Time → time.Duration elapsed := now.Sub(yesterday) fmt.Println(elapsed) // 24h0m0s // Since / Until — shortcuts using time.Now() start := time.Now() // ... do work ... fmt.Println(time.Since(start)) // elapsed since start deadline := now.Add(5 * time.Minute) fmt.Println(time.Until(deadline)) // time remaining
Output
24h0m0s 4m59.999872042s
Benchmarking execution time
Pattern
func benchmark(name string, fn func()) { start := time.Now() fn() elapsed := time.Since(start) fmt.Printf("%s took %v\n", name, elapsed) } benchmark("heavy task", func() { time.Sleep(50 * time.Millisecond) })
Output
heavy task took 50.123456ms
Comparing Times
Before · After · EqualNever use
== to compare time.Time values — it also compares the monotonic clock and location pointer. Use .Equal() for semantic equality.
Before, After, Equal
Comparison
t1 := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC) t2 := time.Date(2026, time.June, 23, 0, 0, 0, 0, time.UTC) t3 := t1 fmt.Println(t1.Before(t2)) // true — t1 is earlier fmt.Println(t2.After(t1)) // true — t2 is later fmt.Println(t1.Equal(t3)) // true — same instant fmt.Println(t1 == t3) // may be false! don't use == // Clamp: check if time is within a range func inRange(t, lo, hi time.Time) bool { return !t.Before(lo) && !t.After(hi) }
Output
true true true true
Timezones
time.Location
Loading and converting locations
Timezones
now := time.Now().UTC() // start in UTC // Load IANA timezone (requires tzdata on system or embed) ny, _ := time.LoadLocation("America/New_York") lon, _ := time.LoadLocation("Europe/London") tok, _ := time.LoadLocation("Asia/Tokyo") // Convert — same instant, different display fmt.Println(now.In(ny)) fmt.Println(now.In(lon)) fmt.Println(now.In(tok)) // Fixed offset (when IANA name is unknown) ist := time.FixedZone("IST", 5*3600+30*60) // +05:30 fmt.Println(now.In(ist)) // Get timezone name + offset name, offset := now.In(ny).Zone() fmt.Printf("%s offset=%d\n", name, offset)
Output
2026-06-23 10:30:05 -0400 EDT 2026-06-23 15:30:05 +0100 BST 2026-06-24 00:30:05 +0900 JST 2026-06-23 21:00:05 +0530 IST EDT offset=-14400
Embed tzdata (no system dependency)
Production tip
// In any .go file (often main.go or a dedicated tz.go) import _ "time/tzdata" // This embeds the full IANA timezone database into your binary, // so LoadLocation works even in scratch containers with no /usr/share/zoneinfo
Unix Timestamps
Unix · UnixMilli · UnixNano
Converting to/from Unix time
Interop
now := time.Now() // time.Time → Unix timestamp fmt.Println(now.Unix()) // seconds since epoch fmt.Println(now.UnixMilli()) // milliseconds fmt.Println(now.UnixMicro()) // microseconds fmt.Println(now.UnixNano()) // nanoseconds // Unix timestamp → time.Time ts := time.Unix(1750000000, 0) // (sec, nsec) fmt.Println(ts) tsMs := time.UnixMilli(1750000000000) fmt.Println(tsMs) // JSON marshaling uses RFC3339 by default type Event struct { At time.Time `json:"at"` }
Output
1750686605 1750686605123 1750686605123456 1750686605123456789 2025-06-15 14:13:20 +0000 UTC 2025-06-15 14:13:20 +0000 UTC
Sleep & Timing
time.Sleep
time.Sleep — pause execution
Sleep
// Pause the current goroutine time.Sleep(500 * time.Millisecond) time.Sleep(2 * time.Second) time.Sleep(1 * time.Minute) // Context-aware sleep (can be cancelled) func sleepCtx(ctx context.Context, d time.Duration) error { select { case <-time.After(d): return nil case <-ctx.Done(): return ctx.Err() } }
Timers
time.TimerA
Timer fires once after the duration. Always stop a timer you no longer need to free resources, and drain its channel when resetting.
One-shot timer
time.NewTimer
timer := time.NewTimer(2 * time.Second) defer timer.Stop() // always clean up select { case t := <-timer.C: fmt.Println("Timer fired at", t) case <-time.After(1 * time.Second): fmt.Println("Timed out waiting for timer") } // time.AfterFunc — callback in new goroutine time.AfterFunc(500*time.Millisecond, func() { fmt.Println("callback fired") })
Resetting a timer safely
Pattern
timer := time.NewTimer(5 * time.Second) // Safe reset pattern if !timer.Stop() { select { case <-timer.C: // drain if already fired default: } } timer.Reset(10 * time.Second)
Tickers
time.TickerA
Ticker fires repeatedly at a fixed interval. Always call ticker.Stop() when done — unlike a channel close, it won't stop on its own.
Periodic work with a Ticker
time.NewTicker
ticker := time.NewTicker(1 * time.Second) done := make(chan struct{}) go func() { for { select { case <-done: return case t := <-ticker.C: fmt.Println("tick at", t.Format(time.Kitchen)) } } }() time.Sleep(5 * time.Second) ticker.Stop() close(done) fmt.Println("ticker stopped")
Output
tick at 2:30PM tick at 2:30PM tick at 2:30PM tick at 2:30PM tick at 2:30PM ticker stopped
Heartbeat / retry with ticker + context
Real-world pattern
func pollUntilDone(ctx context.Context, interval time.Duration) { ticker := time.NewTicker(interval) defer ticker.Stop() for { select { case <-ctx.Done(): fmt.Println("context cancelled, stopping poll") return case <-ticker.C: if checkHealth() { fmt.Println("healthy!") return } fmt.Println("still waiting...") } } }
Quick Reference
All key functions| Function / Method | Returns | Description |
|---|---|---|
| time.Now() | time.Time | Current local time (wall + monotonic) |
| time.Date(y,m,d,h,min,s,ns,loc) | time.Time | Construct a specific time |
| t.Format(layout) | string | Format time using reference layout |
| time.Parse(layout, s) | time.Time, error | Parse a string into time.Time |
| time.ParseInLocation(layout, s, loc) | time.Time, error | Parse respecting a timezone |
| t.Add(d) | time.Time | Add a duration to a time |
| t.AddDate(y,m,d) | time.Time | Calendar-aware date arithmetic |
| t.Sub(u) | time.Duration | Difference between two times |
| time.Since(t) | time.Duration | Elapsed time since t |
| time.Until(t) | time.Duration | Time remaining until t |
| t.Before(u) | bool | t is earlier than u |
| t.After(u) | bool | t is later than u |
| t.Equal(u) | bool | Same instant (timezone-agnostic) |
| t.In(loc) | time.Time | Convert time to different timezone |
| t.UTC() | time.Time | Convert to UTC |
| t.Local() | time.Time | Convert to local time |
| t.Unix() | int64 | Seconds since Unix epoch |
| t.UnixMilli() | int64 | Milliseconds since Unix epoch |
| t.UnixNano() | int64 | Nanoseconds since Unix epoch |
| time.Unix(sec, nsec) | time.Time | time.Time from Unix timestamp |
| t.Truncate(d) | time.Time | Truncate to multiple of d |
| t.Round(d) | time.Time | Round to nearest multiple of d |
| t.IsZero() | bool | Is this the zero time? |
| t.Zone() | string, int | Timezone name and offset |
| time.Sleep(d) | — | Pause goroutine for d |
| time.After(d) | <-chan time.Time | Channel that sends after d |
| time.NewTimer(d) | *time.Timer | One-shot timer |
| time.AfterFunc(d, f) | *time.Timer | Call f in goroutine after d |
| time.NewTicker(d) | *time.Ticker | Repeating ticker every d |
| time.ParseDuration(s) | time.Duration, error | Parse "1h30m" → Duration |
| time.LoadLocation(name) | *time.Location, error | Load IANA timezone |
| time.FixedZone(name, offset) | *time.Location | Fixed UTC offset location |