Question
I am testing concurrent goroutines in Go and want a function to pause for a random amount of time, up to one second. I added this line:
time.Sleep(rand.Int31n(1000) * time.Millisecond)
But the code does not compile, and I get this error:
invalid operation: rand.Int31n(1000) * time.Millisecond (mismatched types int32 and time.Duration)
Why does this happen, and what is the correct way to multiply a duration by an integer in Go?
Short Answer
By the end of this page, you will understand what time.Duration is in Go, why it cannot be multiplied directly by values of a different numeric type, and how to convert integers safely so they work with functions like time.Sleep. You will also see practical examples using random delays, learn common mistakes, and understand how this pattern appears in real Go code.
Concept
time.Duration in Go is a named type that represents a length of time as a number of nanoseconds.
For example:
var d time.Duration = time.Second
Even though time.Duration is based on an integer type internally, Go treats it as its own type. Go is strict about type safety, so values of different types usually cannot be mixed in arithmetic unless you convert them explicitly.
That is why this fails:
rand.Int31n(1000) * time.Millisecond
rand.Int31n(1000)returns anint32time.Millisecondis atime.Duration- Go does not automatically convert
int32totime.Duration
The fix is to convert the random number to time.Duration first:
time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
Now both sides of the multiplication are compatible:
time.Duration(rand.Int31n(1000))is a
Mental Model
Think of time.Duration as a measuring unit like centimeters.
If someone gives you the number 5, that is just a plain number. But if you want to say 5 centimeters, you must attach the unit.
In Go:
rand.Int31n(1000)is just a number of typeint32time.Millisecondis a time unit
Go does not guess that your plain number should become a duration. You must say it explicitly:
time.Duration(rand.Int31n(1000))
Now Go understands: “This number represents a duration count,” so multiplying by time.Millisecond makes sense.
So the mental model is:
- plain integers are just counts
time.Durationis a count with time meaning- convert the count before combining it with time units
Syntax and Examples
The basic pattern is:
time.Duration(number) * time.Unit
Correct syntax
time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
This means:
- generate a random number from
0to999 - convert it to
time.Duration - multiply it by
time.Millisecond - sleep for that amount of time
Example: fixed duration multiplication
package main
import (
"fmt"
"time"
)
func main() {
wait := time.Duration(3) * time.Second
fmt.Println(wait)
}
Output:
3s
Example: random delay
package main
import (
"math/rand"
)
{
rand.Seed(time.Now().UnixNano())
delay := time.Duration(rand.Int31n()) * time.Millisecond
time.Sleep(delay)
}
Step by Step Execution
Consider this code:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
n := rand.Int31n(5)
delay := time.Duration(n) * time.Millisecond
fmt.Println("random number:", n)
fmt.Println("delay:", delay)
time.Sleep(delay)
fmt.Println("done")
}
Step by step:
-
rand.Seed(time.Now().UnixNano())- Initializes the random generator with a changing seed.
- Without this, the program may produce the same sequence each run.
-
n := rand.Int31n(5)- Picks a random
int32from0to4. - Example value:
3
- Picks a random
-
delay := time.Duration(n) * time.Millisecond- Converts
3from to
- Converts
Real World Use Cases
Working with multiplied durations is common in Go applications.
Random delays for testing
You used this pattern for goroutine testing. That is a valid use case when you want to simulate:
- network latency
- slow database queries
- non-deterministic task completion
Example:
time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
Retry with backoff
Programs often wait longer after each failed attempt:
wait := time.Duration(attempt) * time.Second
Polling loops
An app may check a resource every few seconds:
interval := time.Duration(10) * time.Second
Rate limiting
A worker may pause between operations:
time.Sleep(200 * time.Millisecond)
Timeout configuration
Sometimes you compute durations from numeric config values:
secondsFromConfig := 15
%timeout := time.Duration(secondsFromConfig) * time.Second
This pattern is especially useful when values come from:
Real Codebase Usage
In real Go codebases, developers usually compute durations in a small, readable variable first instead of putting everything directly inside time.Sleep.
Common pattern: assign first, use later
delay := time.Duration(rand.Intn(1000)) * time.Millisecond
time.Sleep(delay)
This is easier to debug and log.
Validation pattern
When durations come from config, developers often validate them:
seconds := 5
if seconds < 0 {
seconds = 0
}
timeout := time.Duration(seconds) * time.Second
Backoff and retry logic
for attempt := 1; attempt <= 3; attempt++ {
err := tryRequest()
if err == nil {
return
}
wait := time.Duration(attempt) * time.Second
time.Sleep(wait)
}
Jitter to avoid synchronized retries
In distributed systems, developers add randomness so many processes do not retry at exactly the same moment:
base := 2 * time.Second
jitter := time.Duration(rand.Intn(500)) * time.Millisecond
time.Sleep(base + jitter)
Guarding against bad units
Common Mistakes
1. Mixing numeric types without conversion
Broken code:
time.Sleep(rand.Int31n(1000) * time.Millisecond)
Why it fails:
rand.Int31n(1000)isint32time.Millisecondistime.Duration
Fix:
time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
2. Forgetting the time unit
Broken code:
time.Sleep(time.Duration(1000))
This sleeps for 1000 nanoseconds, not 1000 milliseconds.
Fix:
time.Sleep(time.Duration(1000) * time.Millisecond)
3. Assuming Go does automatic conversion
Broken idea:
var n int = 5
var d time.Duration = n * time.Second
Comparisons
| Concept | What it is | Example | Notes |
|---|---|---|---|
int | General integer type | 5 | Used for counts, indexes, lengths |
int32 | 32-bit integer | rand.Int31n(1000) | Not interchangeable with time.Duration |
time.Duration | Time length in nanoseconds | 2 * time.Second | Used by time.Sleep, timeouts, intervals |
time.Duration vs plain integers
Cheat Sheet
Core rule
When combining numbers with time.Duration, convert the number first.
time.Duration(n) * time.Millisecond
Common examples
wait := time.Duration(5) * time.Second
sleep := time.Duration(rand.Intn(1000)) * time.Millisecond
timeout := time.Duration(configSeconds) * time.Second
Why your original code failed
rand.Int31n(1000) * time.Millisecond
- left side:
int32 - right side:
time.Duration - Go does not mix them automatically
Correct version
time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
Remember the unit
time.Duration(1000) // 1000 nanoseconds
time.Duration(1000) * time.Millisecond // 1000 milliseconds
Useful units
FAQ
Why do I need to convert to time.Duration in Go?
Because Go does not automatically mix different numeric types in arithmetic. time.Duration is a distinct type.
What type is time.Millisecond?
It is a constant of type time.Duration.
Does rand.Intn() also need conversion?
Yes. Even though it returns int, you still need time.Duration(rand.Intn(...)) before multiplying by a duration unit.
What happens if I write time.Duration(1000)?
That means 1000 nanoseconds, because time.Duration stores nanoseconds unless you multiply by a unit like time.Millisecond.
Is 500 * time.Millisecond valid without conversion?
Yes. Untyped numeric constants like 500 can work directly with time.Duration constants.
Should I use rand.Int31n or rand.Intn?
Mini Project
Description
Build a small Go program that simulates multiple worker goroutines finishing at random times. This demonstrates how to create computed delays with time.Duration and use them safely with time.Sleep.
Goal
Create a program that starts several goroutines, gives each one a random delay in milliseconds, and prints when each worker starts and finishes.
Requirements
[
"Start at least 3 goroutines.",
"Each goroutine must sleep for a random duration between 0 and 999 milliseconds.",
"Use time.Duration(...) * time.Millisecond to build the delay.",
"Print a message before and after each sleep.",
"Wait for all goroutines to finish before exiting."
]
Keep learning
Related questions
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.
Convert String to Integer in Go: Idiomatic Parsing with strconv.Atoi
Learn the idiomatic way to convert a string to an int in Go using strconv.Atoi, with examples, errors, and common mistakes.