Unit of time for duration - go

I have in the code
fmt.Println("... ", time.Since(s1))
fmt.Println(".... ", time.Since(s2))
The results for the first is always in µs and for the second in ns (for example 7.081µs, respectively 365ns).
What causes this? How can I control it? I'd like 7081ns to be displayed, always ns/
I looked at the function; how could I interpret it?
// Since returns the time elapsed since t.
// It is shorthand for time.Now().Sub(t).
func Since(t Time) Duration {
var now Time
if t.wall&hasMonotonic != 0 {
// Common case optimization: if t has monotonic time, then Sub will use only it.
now = Time{hasMonotonic, runtimeNano() - startNano, nil}
} else {
now = Now()
}
return now.Sub(t)
}

The fmt package calls the time.Duration.String() method (because time.Duration implements the fmt.Stringer interface) which will use smaller units (milli-, micro-, or nanoseconds) if the duration is less than one second. You cannot control this directly.
You can however convert the number of nanoseconds returned from duration.Nanoseconds() to a string using Itoa, e.g. like this:
formatted := strconv.Itoa(int(time.Since(s2).Nanoseconds())) + "ns"
You can also see this example on the playground

Related

golang conditionals on the time difference (sub)

I have two times, t1 and t2.
To calculate the difference, I use,
diff := t2.sub(t1)
The above code returns the difference like 10m30s, 1h3m59s etc.
I need to create some conditions for the difference.
For example,
if diff <= 5m {
do this
}
if diff > 20m {
do that
}
My question is if there is any built-in way to compare the time difference.
My other option would be to parse returned diff with regex and then compare. But I was looking for some efficient ways like the sub which the time package offers.
t2.Sub(t1) returns a duration, and you can simply use the comparison operators, for example:
d, _ := time.ParseDuration("4m4s")
if d <= 5 * time.Second {
fmt.Println("<= than limit")
} else {
fmt.Println("> than limit")
}
Way 1: When we use sub to get the duration
A very simple alternative is to directly use the output of the sub function. The func sub returns time.Duration type. So just adding .Minutes() method with it would serve the purpose in my case.
t1 := time.Now()
time.Sleep(60011 * time.Millisecond)
t2 := time.Now()
timeDiff := t2.Sub(t1)
fmt.Println(timeDiff)
fmt.Printf("\nIn just minites: %.f\n", timeDiff.Minutes())
Playground
Way 2: When we have the duration in string
If we would have the "difference" as a string ("10m2s") type then I believe we need to use the ParseDuration function. From the godocs ParseDuration
From the doc,
ParseDuration parses a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
I am thinking of using it like the following,
t = "10h10m6s"
timeDiff, _ := time.ParseDuration(t)
numberOfHours := timeDiff.Hours()
numberOfMinutes := timeDiff.Minutes()
numberOfSeconds := timeDiff.Seconds()
numberofNanosec := timeDiff.Nanoseconds()
Find the example snippet on the playground
So in any of the above cases, we can use time.Minutes() to compare the duration.. As #gopher pointed out that to compare with any time range we do not need to convert it to any period of time (e,g Mintues(), Seconds()) but we can just compare with a required time period. As #Haris Osmanagić pointed out that this works for both of the output of ParseDuration and time.Sub() as they both returns time.Duration type. So we can do something like the following,
if timeDiff < 5 * time.Minutes() {
do something
} else if timeDiff > 5 * time.Minutes(){
do something else
} else {
do nothing
}
An example is on the playground.

What is the most time efficient way to guarantee at least one nanosecond has elapsed in Go? time.Sleep(time.Nanosecond) can take milliseconds

I have two function calls that I would like to separate by at least a nanosecond. But I want the delay to be as small as possible.
The code below shows an empty for loop is much more efficient at this than using time.Sleep(time.Nanosecond)
Is there an even more efficient way to guarantee at least one nanosecond has elapsed?
func TimeWaster () {
start := uint64(time.Now().UnixNano())
stop := uint64(time.Now().UnixNano())
fmt.Println(time.Duration(stop-start))//0s
//no nanoseconds pass
start = uint64(time.Now().UnixNano())
time.Sleep(time.Nanosecond)
stop = uint64(time.Now().UnixNano())
fmt.Println(time.Duration(stop-start))//6.9482ms
//much *much* more than one nanosecond passes
start = uint64(time.Now().UnixNano())
for uint64(time.Now().UnixNano()) == start {
//intentionally empty loop
}
stop = uint64(time.Now().UnixNano())
fmt.Println(time.Duration(stop-start))//59.3µs
//much quicker than time.Sleep(time.Nanosecond), but still much slower than 1 nanosecond
}
The package you're using strangely enforces uniqueness of values by time, so all you need to do is loop until the time package is no longer reporting the same value for the current nanosecond. This doesn't happen after 1 nanosecond, in fact the resolution of the UnixNano is about 100 nanoseconds on my machine and only updates about every 0.5 milliseconds.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().UnixNano())
smallWait()
fmt.Println(time.Now().UnixNano())
}
func smallWait() {
for start := time.Now().UnixNano(); time.Now().UnixNano() == start; {}
}
The loop is pretty self-explanatory, just repeat until the UnixNano() is different

How to get millisecond value of a timestamp

Go has methods to extract almost every component of a timestamp, eg time.Second(), time.Nano(), but none to extract the millisecond portion of a timestamp.
How does one extract the millisecond value of a timestamp.
eg, in the case of a timestamp like:
2021-01-07 10:33:06.511
i want to extract 511
To access the fraction seconds, you may use time.Nanosecond(). And if we convert it to time.Duration (time.Duration is exactly the nanoseconds count), we can take advantage of its Duration.Milliseconds() method (which of course does no magic but code will be clearer and easier to read):
func extractMs(t time.Time) int64 {
return time.Duration(t.Nanosecond()).Milliseconds()
}
Try it on the Go Playground.
there is an answer in the comments, but i want to post here to be cannonical:
func extractMillisecond(t time.Time) int {
ms := time.Duration(t.Nanosecond()) / time.Millisecond
return int(ms)
}

How uber-go/ratelimit algorithm works?

I tried to understand uber's opensource implementation of ratelimit, but a little confused
full code are as followings:
// Take blocks to ensure that the time spent between multiple
// Take calls is on average time.Second/rate.
func (t *limiter) Take() time.Time {
newState := state{}
taken := false
for !taken {
now := t.clock.Now()
previousStatePointer := atomic.LoadPointer(&t.state)
oldState := (*state)(previousStatePointer)
newState = state{}
newState.last = now
// If this is our first request, then we allow it.
if oldState.last.IsZero() {
taken = atomic.CompareAndSwapPointer(&t.state, previousStatePointer, unsafe.Pointer(&newState))
continue
}
// sleepFor calculates how much time we should sleep based on
// the perRequest budget and how long the last request took.
// Since the request may take longer than the budget, this number
// can get negative, and is summed across requests.
newState.sleepFor += t.perRequest - now.Sub(oldState.last)
// We shouldn't allow sleepFor to get too negative, since it would mean that
// a service that slowed down a lot for a short period of time would get
// a much higher RPS following that.
if newState.sleepFor < t.maxSlack {
newState.sleepFor = t.maxSlack
}
if newState.sleepFor > 0 {
newState.last = newState.last.Add(newState.sleepFor)
}
taken = atomic.CompareAndSwapPointer(&t.state, previousStatePointer, unsafe.Pointer(&newState))
}
t.clock.Sleep(newState.sleepFor)
return newState.last
}
I realized this is a lock-free algorithm, but I know little about this topic.
appreciated if anyone happend to know this algorithm and offer me some answers/docs/blogs.

Why is time.Since returning negative durations on Windows?

I have been trying to work with some go, and have found some weird behavior on windows. If I construct a time object from parsing a time string in a particular format, and then use functions like time.Since(), I get negative durations.
Code sample:
package main
import (
"fmt"
"time"
"strconv"
)
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, _:= time.Parse(layout, dateStr)
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30*time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
fmt.Println("Duration in seconds: " + strconv.Itoa(int(duration.Seconds())))
}
If you run it on Linux or the Go Playground link, you get the result as Duration in seconds: 30 which is expected.
However, on Windows, running the same piece of code with Go 1.10.3 gives Duration in seconds: -19769.
I've banged my head on this for hours. Any help on what I might be missing?
The only leads I've had since now are that when go's time package goes to calculate the seconds for both time objects (time.Now() and my parsed time object), one of them has the property hasMonotonic and one doesn't, which results in go calculating vastly different seconds for both.
I'm not the expert in time, so would appreciate some help. I was going to file a bug for Go, but thought to ask here from the experts if there's something obvious I might be missing.
I think I figured out what the reason for the weird behavior of your code snippet is and can provide a solution. The relevant docs read as follows:
since returns the time elapsed since t. It is shorthand for time.Now().Sub(t).
But:
now returns the current local time.
That means you are formatting timeOlder and subtract it from an unformatted local time. That of course causes unexpected behavior. A simple solution is to parse the local time according to your format before subtracting timeOlder from it.
A solution that works on my machine (it probably does not make a lot of sense to give a playground example, though):
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, err := time.Parse(layout, dateStr)
// check the error!
if err != nil {
log.Fatalf("error while parsing time: %s\n", err)
}
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30 * time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
// replace time.Since() with a correctly parsed time.Now(), because
// time.Since() returns the time elapsed since the current LOCAL time.
t := time.Now().Format("2006-01-02T15:04:05.000Z")
timeNow := convertToTimeObject(t)
// print the different results
fmt.Println("duration in seconds:", strconv.Itoa(int(duration.Seconds())))
fmt.Printf("duration: %v\n", timeNow.Sub(timeOlder))
}
Outputs:
duration in seconds: 14430
duration: 30s

Resources