Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
122: time.Now, time.Since, and Durations
I see this all the time when developers move to Go from languages like Python or JavaScript: they assume that if they want to represent a span of time, they can just use an integer. They think, "I'll just pass the number 5 to the sleep function, and the language will know I mean 5 seconds."
Let's look at why that fails miserably in Go.
The "5 Nanosecond" Trap
package main
import (
"fmt"
"time"
)
func main() {
seconds := 5
// You might think this sleeps for 5 seconds...
time.Sleep(time.Duration(seconds))
fmt.Println("Woke up!")
}
If you run this, "Woke up!" prints almost instantly. You didn't sleep for 5 seconds; you slept for 5 nanoseconds. In Go, the time.Duration type is actually an int64 representing nanoseconds. When you cast an integer directly to a Duration, you aren't telling Go the unit—you're just giving it the raw count of nanoseconds.
Scaling Durations with Constants
To get the behavior you actually want, you have to multiply your value by one of the predefined constants in the time package, such as time.Millisecond, time.Second, or time.Hour. These constants are themselves time.Duration types.
package main
import (
"fmt"
"time"
)
func main() {
seconds := 5
// Multiply the integer by the unit constant
time.Sleep(time.Duration(seconds) * time.Second)
fmt.Println("Now we actually waited 5 seconds.")
}
Notice that I still cast seconds to time.Duration first. Go is strict about types; you can't multiply a time.Duration by a plain int. You have to make sure both sides of the operator are the same type. I've found that getting into the habit of casting the variable first makes the code much more readable.
Measuring Execution with time.Since
Once you're comfortable with Durations, you'll often find yourself needing to measure how long a specific piece of logic takes to run. You could call time.Now() at the start, call it again at the end, and subtract the two. But that's verbose.
Instead, use time.Since(). It's a helper function that captures the current time and subtracts the time you passed in, returning a time.Duration.
start := time.Now()
// Simulate some heavy work
doExpensiveCalculation()
elapsed := time.Since(start)
fmt.Printf("The calculation took %s\n", elapsed)
The beauty here is that time.Duration has a built-in String() method. When you print it using %s or fmt.Println, Go automatically formats it into a human-readable string like "1.5s" or "250ms", so you don't have to do the math to figure out if you're looking at milliseconds or microseconds.
📋 Practical Task
Build a Simulated Network Latency Tracker
Create a program that simulates a series of three "API requests." Each request should take a random amount of time to complete (between 100ms and 1000ms).
- Use
time.Now()andtime.Since()to track the duration of each individual request. - Print the duration of each request as it finishes.
- Track the total elapsed time for all three requests combined.
- At the end, print the total time spent waiting.
Hint: To get a random duration, you can generate a random integer and multiply it by time.Millisecond.
There are no comments for now.