Reputation: 137574
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?
Upvotes: 508
Views: 352888
Reputation: 1200
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
Upvotes: 14
Reputation: 1015
You can use time.ParseDuration.
ms := rand.Int31n(1000)
duration, err := time.ParseDuration(fmt.Sprintf(
"%vms",
ms,
))
Upvotes: 0
Reputation: 23963
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)
Upvotes: 761
Reputation: 481
My turn:
https://play.golang.org/p/RifHKsX7Puh
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:
Upvotes: 0
Reputation: 54869
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.
Upvotes: 15
Reputation: 1
For multiplication of variable to time.Second using following code
oneHr:=3600
addOneHrDuration :=time.Duration(oneHr)
addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)
Upvotes: -4
Reputation: 7681
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: https://golang.org/pkg/time/#Duration
seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
Upvotes: 27
Reputation: 27889
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.
Upvotes: 2
Reputation: 222531
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.
Upvotes: 91