Skip to Content
Course content

122: time.Now, time.Since, and Durations

Click on the "Edit" button in the top corner of the screen to edit your slide content.

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() and time.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.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.