Subscribe to the Ardan Labs Insider

You’ll get our FREE Video Series & special offers on upcoming training events along with notifications on our latest blog posts.

Included in your subscription
  • Access to our free video previews
  • Updates on our latest blog posts
  • Discounts on upcoming events

Valid email required.

Submit failed. Try again or message us directly at

Thank You for Subscribing

Check your email for confirmation.

Go's time.Duration Type Unravelled

Author image
William Kennedy

I have been struggling with using the Time package that comes in the Go standard library. My struggles have come from two pieces of functionality. First, trying to capture the number of milliseconds between two different time periods. Second, comparing that duration in milliseconds against a pre-defined time span. It sounds like a no brainier but like I said, I have been struggling.

In the Time package there is a custom type called Duration and a set of helper constants:

type Duration int64

const (
  Nanosecond Duration = 1
  Microsecond = 1000 * Nanosecond
  Millisecond = 1000 * Microsecond
  Second = 1000 * Millisecond
  Minute = 60 * Second
  Hour = 60 * Minute

I looked at this maybe 1000 times but it didn’t mean anything to me. I just want to compare two time periods, get the duration back, compare the duration and do something if the right amount of time has elapsed. I could not for the life of me understand how this structure was going to help me unravel this mystery.

I wrote this Test function but it didn’t work.

func Test() {
  var waitFiveHundredMilliseconds int64 = 500

  startingTime := time.Now().UTC()
  time.Sleep(10 * time.Millisecond)
  endingTime := time.Now().UTC()

  var duration time.Duration = endingTime.Sub(startingTime)
  var durationAsInt64 = int64(duration)

  if durationAsInt64 >= waitFiveHundredMilliseconds {
    fmt.Printf("Time Elapsed : Wait[%d] Duration[%d]\n",
       waitFiveHundredMilliseconds, durationAsInt64)
  } else {
    fmt.Printf("Time DID NOT Elapsed : Wait[%d] Duration[%d]\n",
       waitFiveHundredMilliseconds, durationAsInt64)

When I ran the Test function and look at the output the code thinks that 500 milliseconds have elapsed.

Time Elapsed : Wait[500] Duration[10724798]

So what went wrong? I looked at the Duration type and constants again.

type Duration int64

const (
  Nanosecond Duration = 1
  Microsecond = 1000 * Nanosecond
  Millisecond = 1000 * Microsecond
  Second = 1000 * Millisecond
  Minute = 60 * Second
  Hour = 60 * Minute

The basic unit of time for the Duration type is a Nanosecond. Ah, that is why when casting a Duration type that contains 10 milliseconds to an int64 I get 10,000,000.

So direct casting is not going to work. I need a different strategy and a better understanding of how to use and convert the Duration type.

I know it would be best to use the Duration type natively. This will minimize problems when using the type. Based on the constant values, I can create a Duration type variable in the following ways:

func Test() {
  var duration_Milliseconds time.Duration = 500 * time.Millisecond
  var duration_Seconds time.Duration = (1250 * 10) * time.Millisecond
  var duration_Minute time.Duration = 2 * time.Minute

  fmt.Printf("Milli [%v]\nSeconds [%v]\nMinute [%v]\n",

I created 3 variables of type Duration. Then by using the time constants, I am able to create the correct duration time span values. When I use the standard library Printf function and the %v operator I get the following output:

Milli [500ms]
Seconds [12.5s]
Minute [2m0s]

This is very cool. The Printf function knows how to natively display a Duration type. Based on the value in each Duration variable, the Printf function prints the value in the proper time period. I am also getting the values I expected.

The Duration type does have member functions that will convert the value of the Duration variable to a native Go type, either in int64 or float64 respectively:

func Test() {
  var duration_Seconds time.Duration = (1250 * 10) * time.Millisecond
  var duration_Minute time.Duration = 2 * time.Minute

  var float64_Seconds float64 = duration_Seconds.Seconds()
  var float64_Minutes float64 = duration_Minute.Minutes()

  fmt.Printf("Seconds [%.3f]\nMinutes [%.2f]\n",

I noticed pretty quickly that there is no Milliseconds function. There is a function for every other time unit but Milliseconds. When I display the Seconds and Minutes natively I get the following output as expected:

Seconds [12.500]
Minutes [2.00]

However I need the Milliseconds, So why is the Milliseconds function missing?

The designers of Go didn’t want to lock me into a single native type for the Milliseconds. They wanted me to have options.

The following code converts the value of the Duration variable to Milliseconds as both an int64 and float64:

func Test() {
  var duration_Milliseconds time.Duration = 500 * time.Millisecond

  var castToInt64 int64 = duration_Milliseconds.Nanoseconds() / 1e6
  var castToFloat64 float64 = duration_Milliseconds.Seconds() * 1e3

  fmt.Printf("Duration [%v]\ncastToInt64 [%d]\ncastToFloat64 [%.0f]\n",

If I divide the Nanoseconds by 1e6 I get the Milliseconds as a int64. If I multiply the Seconds by 1e3 I get the Milliseconds as a float64.

Here is the output:

Duration [500ms]
castToInt64 [500]
castToFloat64 [500]

If you are wondering what 1e6 or 1e3 represents you are not alone:

1e3 = 103 = One Thousand = 1 plus 3 0’s

1e6 = 106 = One Million  = 1 plus 6 0’s

Now that I understand what a Duration type is and how best to use and manipulate it, I have my final test example using Milliseconds:

func Test() {
  var waitFiveHundredMilliseconds time.Duration = 500 * time.Millisecond

  startingTime := time.Now().UTC()
  time.Sleep(600 * time.Millisecond)
  endingTime := time.Now().UTC()

  var duration time.Duration = endingTime.Sub(startingTime)

  if duration >= waitFiveHundredMilliseconds {
    fmt.Printf("Wait %v\nNative [%v]\nMilliseconds [%d]\nSeconds [%.3f]\n",

I get the following output:

Wait 500ms
Native [601.091066ms]
Milliseconds [601]
Seconds [0.601]

Instead of comparing native types to determine if the time has elapsed I am comparing two Duration types. This is much cleaner. When displaying the values I am using the Duration type custom formatting and converting the value of the Duration variable to Milliseconds as both an int64 and float64.

It took a while but eventually using the Duration type started to make sense. As always I hope this helps someone else navigate using the Duration type in their Go applications.

Go Training

We have taught Go to thousands of developers all around the world since 2014. There is no other company that has been doing it longer and our material has proven to help jump start developers 6 to 12 months ahead of their knowledge of Go. We know what knowledge developers need in order to be productive and efficient when writing software in Go.

Our classes are perfect for both experienced and beginning engineers. We start every class from the beginning and get very detailed about the internals, mechanics, specification, guidelines, best practices and design philosophies. We cover a lot about "if performance matters" with a focus on mechanical sympathy, data oriented design, decoupling and writing production software.

Capital One
Red Ventures

Interested in Ultimate Go Corporate Training and special pricing?

Let’s Talk Corporate Training!

Join Our Online
Education Program

Our courses have been designed from training over 30,000 engineers since 2013, and they go beyond just being a language course. Our goal is to challenge every student to think about what they are doing and why.