chrono
is a small collection of useful time-based types and helpers. It
provides:
-
go.mway.dev/chrono
- An exported
Nanotime
function, which provides access to the underlying system clock (viaruntime.nanotime
)
- An exported
-
go.mway.dev/chrono/clock
- A common
Clock
interface shared by all clocks - Monotonic and wall
Clock
s - A
ThrottledClock
to provide configurable time memoization to reduce time-based syscalls - A
FakeClock
implementation, to support mocking time - A lightweight
Stopwatch
for trivially (and continuously) measuring elapsed time
- A common
-
go.mway.dev/periodic
- A [
Handle
][periodic-handler-doc] to manage functions that are run periodically viaStart
- A [
- go.mway.dev/chrono/rate
These packages are intended for general use, and as a replacement for the long-archived github.com/andres-erbsen/clock package.
To start using a Clock
, first determine whether the goal is to
tell time, or to measure time:
- When telling time, wall clocks are necessary. Use NewWallClock.
- When measuring time, monotonic clocks are preferable, though in most cases a wall clock can be used as well. Use NewMonotonicClock.
The only difference between a wall clock and a monotonic clock is the time
source being used, which in this implementation is either a TimeFunc
or a NanotimeFunc
.
After selecting a type of clock, simply construct and use it:
package main
import (
"time"
"go.mway.dev/chrono/clock"
)
func main() {
var (
clk = clock.NewWallClock()
now = clk.Now() // time.Time
nanos = clk.Nanotime() // int64
stopwatch = clk.NewStopwatch()
ticker = clk.NewTicker(time.Second)
timer = clk.NewTimer(3*time.Second)
)
fmt.Printf("It is now: %s (~%d)\n", now, nanos)
func() {
for {
select {
case <-ticker.C:
fmt.Println("Tick!")
case <-timer.C:
fmt.Println("Done!")
return
}
}
}()
fmt.Println("Ticker/timer took", stopwatch.Elapsed())
// etc.
}
The goal of Clock
is to be comparable to using the standard
library time
, i.e. any common time
-related functions should
be provided as part of the Clock
API.
TODO
In some cases, it may be desirable to limit the number of underlying time-based
syscalls being made, for example when needing to attribute time within a tight
loop. Rather than needing to throttle or debounce such calls themselves, users
can use a ThrottledClock
, which does this at a
configurable resolution:
// Use monotonic time that only updates once per second
clk := clock.NewThrottledMonotonicClock(time.Second)
defer clk.Stop() // free resources
// Issue an arbitrary number of time-based calls
for i := 0; i < 1_000_000; i++ {
clk.Nanotime()
}
A background routine updates the clock's time from the configured source at
the specified interval, and time-based calls on a ThrottledClock
use the
internally cached time.
Pull requests are welcome, and all feedback is appreciated!