How to multiply duration by integer?

To test concurrent goroutines, I added a line to a function to make it take a random time to return (up to one second)

time.Sleep(rand.Int31n(1000) * time.Millisecond) 

However when I compiled, I got this error

.\crawler.go:49: invalid operation: rand.Int31n(1000) * time.Millisecond (mismatched types int32 and time.Duration)

Any ideas? How can I multiply a duration?

9 Answers

int32 and time.Duration are different types. You need to convert the int32 to a time.Duration:

time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond) 
12

You have to cast it to a correct format Playground.

yourTime := rand.Int31n(1000) time.Sleep(time.Duration(yourTime) * time.Millisecond) 

If you will check documentation for sleep, you see that it requires func Sleep(d Duration) duration as a parameter. Your rand.Int31n returns int32.

The line from the example works (time.Sleep(100 * time.Millisecond)) because the compiler is smart enough to understand that here your constant 100 means a duration. But if you pass a variable, you should cast it.

2

In Go, you can multiply variables of same type, so you need to have both parts of the expression the same type.

The simplest thing you can do is casting an integer to duration before multiplying, but that would violate unit semantics. What would be multiplication of duration by duration in term of units?

I'd rather convert time.Millisecond to an int64, and then multiply it by the number of milliseconds, then cast to time.Duration:

time.Duration(int64(time.Millisecond) * int64(rand.Int31n(1000))) 

This way any part of the expression can be said to have a meaningful value according to its type. int64(time.Millisecond) part is just a dimensionless value - the number of smallest units of time in the original value.

If walk a slightly simpler path:

time.Duration(rand.Int31n(1000)) * time.Millisecond 

The left part of multiplication is nonsense - a value of type "time.Duration", holding something irrelevant to its type:

numberOfMilliseconds := 100 // just can't come up with a name for following: someLHS := time.Duration(numberOfMilliseconds) fmt.Println(someLHS) fmt.Println(someLHS*time.Millisecond) 

And it's not just semantics, there is actual functionality associated with types. This code prints:

100ns 100ms 

Interestingly, the code sample here uses the simplest code, with the same misleading semantics of Duration conversion:

seconds := 10

fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

It's nice that Go has a Duration type -- having explicitly defined units can prevent real-world problems.

And because of Go's strict type rules, you can't multiply a Duration by an integer -- you must use a cast in order to multiply common types.

/* MultiplyDuration Hide semantically invalid duration math behind a function */ func MultiplyDuration(factor int64, d time.Duration) time.Duration { return time.Duration(factor) * d // method 1 -- multiply in 'Duration' // return time.Duration(factor * int64(d)) // method 2 -- multiply in 'int64' } 

The official documentation demonstrates using method #1:

To convert an integer number of units to a Duration, multiply:

seconds := 10 fmt.Print(time.Duration(seconds)*time.Second) // prints 10s 

But, of course, multiplying a duration by a duration should not produce a duration -- that's nonsensical on the face of it. Case in point, 5 milliseconds times 5 milliseconds produces 6h56m40s. Attempting to square 5 seconds results in an overflow (and won't even compile if done with constants).

By the way, the int64 representation of Duration in nanoseconds "limits the largest representable duration to approximately 290 years", and this indicates that Duration, like int64, is treated as a signed value: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292, and that's exactly how it is implemented:

// A Duration represents the elapsed time between two instants // as an int64 nanosecond count. The representation limits the // largest representable duration to approximately 290 years. type Duration int64 

So, because we know that the underlying representation of Duration is an int64, performing the cast between int64 and Duration is a sensible NO-OP -- required only to satisfy language rules about mixing types, and it has no effect on the subsequent multiplication operation.

If you don't like the the casting for reasons of purity, bury it in a function call as I have shown above.

3

Confused by some of the comments & discussions on multiplying Duration with Duration, I played around a bit with the units and functions and got this:

time.Second = 1s time.Minute = 1m0s time.Duration(1) = 1ns time.Duration(1) * time.Millisecond = 1ms time.Duration(1) * time.Second = 1s time.Duration(1) * time.Minute = 1m0s 

Just multiply it like this:

time.Sleep(1000 * time.Millisecond) 

You don't need to convert it.


Reasoning:

1000 is an untyped literal constant with a default type of integer, it has an ideal type.

1000 * time.Millisecond can be used directly because, Go converts the untyped constants to numeric types automatically. Here, it converts 1000 to time.Duration automatically, because it's an alias to Int64.

Millisecond defined like this:

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

Millisecond has time.Duration type, but, underlying, it's an int64 which is assignable and can be used by a numeric untyped integer.


👉 I wrote about these details here in this post.

Go Default Types Cheatsheet

My turn:

package main import ( "fmt" "time" ) func main() { var n int = 77 v := time.Duration( 1.15 * float64(n) ) * time.Second fmt.Printf("%v %T", v, v) } 

It helps to remember the simple fact, that underlyingly the time.Duration is a mere int64, which holds nanoseconds value.

This way, conversion to/from time.Duration becomes a formality. Just remember:

  • int64
  • always nanosecs

You can use time.ParseDuration.

ms := rand.Int31n(1000) duration, err := time.ParseDuration(fmt.Sprintf( "%vms", ms, )) 

For multiplication of variable to time.Second using following code

 oneHr:=3600 addOneHrDuration :=time.Duration(oneHr) addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second) 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like