time
The time package is the right kind of opinionated: a Time is location-aware, durations are typed, and the layout-based parser is unique to Go but catches a class of formatting bugs at compile time. Default to time.Now().UTC() at the API boundary, and use time.Time for everything in between — never a string.
Parse, format, compare, schedule, and benchmark
EXAMPLE
package main
import (
"fmt"
"time"
)
func main() {
// 1) Now, UTC, and the local zone
now := time.Now()
fmt.Println(now) // 2026-06-11 09:30:00 +1000 AEST
fmt.Println(now.UTC()) // 2026-06-10 23:30:00 +0000 UTC
// 2) Parse with the famous reference layout: Mon Jan 2 15:04:05 MST 2006
t, err := time.Parse(time.RFC3339, "2026-06-11T09:30:00+10:00")
if err != nil { panic(err) }
fmt.Println(t.Format("Mon 02 Jan 2006 3:04pm"))
// 3) Durations are a real type, not a number-of-seconds-in-disguise
timeout := 30 * time.Second
tick := 250 * time.Millisecond
fmt.Println("timeout in seconds:", timeout.Seconds())
// 4) Comparisons and arithmetic
deadline := time.Now().Add(5 * time.Minute)
if time.Now().Before(deadline) { fmt.Println("not yet") }
delta := deadline.Sub(time.Now()) // returns time.Duration
fmt.Println("delta:", delta.Round(time.Second))
// 5) Time-zone aware: load IANA zones
syd, _ := time.LoadLocation("Australia/Sydney")
mumbai, _ := time.LoadLocation("Asia/Kolkata")
standup := time.Date(2026, 6, 12, 9, 0, 0, 0, syd)
fmt.Println("standup in Mumbai:", standup.In(mumbai))
// 6) Tickers and timers — channel-based scheduling
t1 := time.NewTicker(tick)
defer t1.Stop()
stop := time.After(2 * time.Second)
loop:
for {
select {
case <-t1.C:
fmt.Println("tick")
case <-stop:
break loop
}
}
// 7) Benchmark a block with time.Since (no need for a separate library)
start := time.Now()
heavyWork()
fmt.Println("heavyWork took", time.Since(start))
// 8) Truncate / Round for bucketing — group events into 5-min bins
bucket := now.Truncate(5 * time.Minute)
fmt.Println("bucket:", bucket)
// 9) Monotonic clock — Sub and Since use it so leap seconds and NTP
// adjustments do not throw off short measurements.
}
func heavyWork() { time.Sleep(100 * time.Millisecond) }
Why it matters
For wall-clock comparisons between events on different machines, always use Unix or UnixNano + clock-skew tolerance. For measuring elapsed time on one machine, use the monotonic clock via time.Since/Sub — it is immune to wall-clock jumps and NTP adjustments that would otherwise produce negative durations.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…