Documentation
¶
Overview ¶
Package dtime provides tools that FFS.
Externally-consumable things provided here:
dtime.Now() is equivalent to time.Now(), except that you can override it, if necessary, to have control over time for testing.
dtime.FakeTime is a class that provides explicit control over a "fake" clock, again for testing. The simplest pattern here is to instantiate a FakeTime, use its Step or StepSec methods to control when time passes, and use its Now method instead of time.Now to get the time.
dtime.SleepWithContext is like time.Sleep(), but it does the right thing when a context is involved.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Now ¶
Now is a clock function. It starts out as an alias to time.Now, so if you simply use dtime.Now instead of time.Now, your program will continue to function exactly as it did before.
The power of dtime.Now is that you can use dtime.SetNow to swap in a different clock function for testing, so that you have explicit control over the passage of time. dtime.FakeTime is an obvious choice here, as shown in the example.
Example ¶
This example uses a dtime.FakeTime to change the behavior of dtime.Now, allowing explicit control of the passage of time.
package main
import (
"fmt"
"time"
"github.com/datawire/dlib/dtime"
)
func main() {
ft := dtime.NewFakeTime()
dtime.SetNow(ft.Now)
// At the start, ft.Now and dtime.Now should give the same answer.
start := ft.Now()
now := dtime.Now()
fmt.Printf("%d\n", int(now.Sub(start)))
// If we step ft by five minutes, dtime.Now should reflect that.
ft.Step(5 * time.Minute)
now = dtime.Now()
fmt.Printf("%d\n", int(now.Sub(start)/time.Second))
// When all is said and done, ft.TimeSinceBoot() should also tell
// us that we've stepped ft by five minutes.
fmt.Printf("%s\n", ft.TimeSinceBoot())
}
Output: 0 300 5m0s
func SetNow ¶
SetNow overrides the definition of dtime.Now.
Note that overriding dtime.Now will (obviously) override it for the entire process. Note also that it is generally a bad idea to swap the clock in the middle of a program run and expect sane things to happen, if your program pays any attention to the clock at all.
func SleepWithContext ¶
SleepWithContext pauses the current goroutine for at least the duration d, or until the Context is done, whichever happens first.
You may be thinking, why not just do:
select {
case <-ctx.Done():
case <-time.After(d):
}
well, time.After can't get garbage collected until the timer expires, even if the Context is done. What this function provides is properly stopping the timer so that it can be garbage collected sooner.
https://medium.com/@oboturov/golang-time-after-is-not-garbage-collected-4cbc94740082
Types ¶
type FakeTime ¶
type FakeTime struct {
// contains filtered or unexported fields
}
FakeTime keeps track of fake time for us, so that we don't have to rely on the real system clock. This can make life during testing much, much easier -- rather than needing to wait forever, you can control the passage of time however you like.
To use FakeTime, use NewFakeTime to instantiate it, then Step (or StepSec) to change its current time. FakeTime also remembers its boot time (the time when it was instantiated) so that you can meaningfully talk about how much fake time has passed since boot and, if necessary, relate fake times to actual system times.
Example ¶
package main
import (
"fmt"
"time"
"github.com/datawire/dlib/dtime"
)
func main() {
ft := dtime.NewFakeTime()
// At boot, ft.Now() and ft.BootTime() will be identical...
if ft.Now() == ft.BootTime() {
fmt.Println("Equal!")
} else {
fmt.Println("Whoa, Now and BootTime don't match at boot??")
}
// ...and TimeSinceBoot will be 0.
fmt.Printf("%d\n", ft.TimeSinceBoot()/time.Second)
// After that, we can declare that 10s have passed...
ft.StepSec(10)
// ...and we should see that in TimeSinceBoot.
fmt.Printf("%d\n", ft.TimeSinceBoot()/time.Second)
// But, of course, we're not limited to seconds.
ft.Step(2 * time.Hour)
fmt.Printf("%s\n", ft.TimeSinceBoot())
}
Output: Equal! 0 10 2h0m10s
func NewFakeTime ¶
func NewFakeTime() *FakeTime
NewFakeTime creates a new FakeTime structure, booted at the current time. Once instantiated, its Now method is a drop-in replacement for time.Now.
func (*FakeTime) BootTime ¶
BootTime returns the real system time at which the FakeTime was instantiated, in case it's needed.
This is an accessor because we don't really want people changing the boot time after boot.
func (*FakeTime) Now ¶
Now returns the current fake time. It is a drop-in replacement for time.Now, and is particularly suitable for use with dtime.SetNow and dtime.Now.
func (*FakeTime) Step ¶
Step steps a FakeTime by the given duration. Any duration may be used, with all the obvious concerns about stepping the fake clock into the past.
func (*FakeTime) StepSec ¶
StepSec steps a FakeTime by a given number of seconds. Any number of seconds is valid, with all the obvious concerns about stepping the fake clock into the past.
This is a convenience to allow writing unit tests that don't have to have "* time.Second" scattered over and over and over again through everything.
func (*FakeTime) TimeSinceBoot ¶
TimeSinceBoot returns the amount of fake time that has passed since the FakeTime was instantiated.