Day 038 — time: Durations, Formatting & Timers¶
Month 2 · Week 2 · ⬅ Day 037 · Day 039 ➡ · Journal index
🎯 Learning Objective¶
Work confidently with time.Time and time.Duration: do duration arithmetic, parse/format with Go's reference layout, and use timers/tickers without leaking them.
📚 Topics¶
time.Duration(int64 nanoseconds) · unit constants ·ParseDuration- The reference layout
Mon Jan 2 15:04:05 MST 2006 Format/Parse· prebuilt layouts (RFC3339,Kitchen)time.After,NewTimer,NewTicker,time.Since/Until- Monotonic vs wall clock
📖 Reading / Sources¶
-
timepackage docs -
time.Time.Format— the reference layout - The Go Blog — package time / monotonic clocks
📝 Notes¶
time.Durationis an int64 count of nanoseconds, not seconds. Always build it from unit constants:90 * time.Minute, never a bare90→ [[duration-is-nanoseconds]].- Time math uses methods, not operators:
t.Add(d),t.Sub(t2)(returns aDuration),time.Since(t)(=Now().Sub(t)),time.Until(t).Round/Truncatesnap a duration/time to a unit. - Formatting uses a magic reference date, not strftime:
Mon Jan 2 15:04:05 MST 2006(numerically01/02 03:04:05PM '06 -0700). You write the layout as that exact date in the shape you want → [[reference-time-layout]]. - Prefer the prebuilt layout constants when they fit:
time.RFC3339,time.DateOnly,time.Kitchen.Parseis the inverse ofFormatusing the same layout string. - Time zones matter:
time.Now()is local; use.UTC()for storage/logs.Parsewithout a zone in the layout yields UTC;ParseInLocationcontrols it. - Timers/tickers:
time.After(d)returns a<-chan Timethat fires once — perfect in aselectfor a timeout. (It can't be stopped; for tight loops prefer a reusableTimer.)time.NewTimer(d)is the stoppable one-shot;Stop()it when no longer needed.time.NewTicker(d)fires repeatedly; you mustStop()it (usuallydefer) or it leaks a goroutine/resource forever → [[always-stop-ticker]].- Monotonic clock:
time.Now()embeds a monotonic reading, soSub/Sincemeasure true elapsed time even if the wall clock jumps (NTP/DST). Don't measure elapsed time by subtracting two formatted wall times.
💻 Code Examples¶
d := 90 * time.Minute
fmt.Println(d, d.Hours()) // 1h30m0s 1.5
t := time.Date(2026, time.August, 2, 15, 4, 5, 0, time.UTC)
fmt.Println(t.Format("2006-01-02 15:04")) // 2026-08-02 15:04
select {
case r := <-work:
use(r)
case <-time.After(50 * time.Millisecond): // one-shot timeout
fmt.Println("timed out")
}
Full code:
examples/month-02/time-timers/main.go· Run:go run ./examples/month-02/time-timers
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
Humanize(d) → compact 2d3h4m5s strings |
✅ | exercises/month-02/week-2/humandur |
🐛 Mistakes Made¶
- Wrote
time.Sleep(100)expecting 100 ms — it's 100 nanoseconds. Needs100 * time.Millisecond. - Tried strftime codes (
%Y-%m-%d) inFormat→ use the reference date2006-01-02instead. - Forgot
defer ticker.Stop()and leaked a goroutine in a long-running loop.
❓ Open Questions¶
- When is
time.Tick(the fire-and-forget helper) acceptable, given it can never be stopped?
🧠 Active Recall (answer without looking)¶
-
Q: What is the reference time you use to build a
Format/Parselayout, and why that value?
A
`Mon Jan 2 15:04:05 MST 2006` — chosen because its components are the sequence 1,2,3,4,5,6,7 (month=1, day=2, hour=3pm=15, minute=4, second=5, year=06, zone=-0700). You write the date in the shape you want output. -
Q: Why must you
Stop()atime.Ticker, but atime.Afterchannel needs no cleanup?
A
A `Ticker` keeps firing forever and holds runtime resources/a goroutine until stopped — leaking one is a real leak. `time.After` is a single-shot timer that fires once and is garbage-collected after; nothing to stop (though a `Timer` you create and abandon early should be `Stop()`ed).
🪶 Feynman Reflection¶
A Duration is just a big nanosecond counter, so you scale it with unit constants. Formatting is unusual: instead of cryptic %Y codes, Go shows you one specific date — January 2nd, 2006, 3:04:05 PM — and asks you to type that date the way you want yours to look. Timers are alarm clocks: After rings once, a Ticker rings on a schedule until you unplug it.
🕳️ Knowledge Gaps¶
- Subtleties of
RoundvsTruncateacross DST boundaries. time.Timer.Resetcorrectness with a drained vs non-drained channel.
✅ Summary¶
I can do duration math, parse/format with the reference layout, choose After/Timer/Ticker correctly, and measure elapsed time with the monotonic clock via time.Since.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 039: the
net/httpclient — building requests, reading responses, and closing bodies.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦🟦⬜⬜⬜ | 🟦🟦🟦⬜⬜ |
Suggested commit: feat(examples): time durations, formatting, and timers (day 038)