time

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2025 License: MIT Imports: 4 Imported by: 1

README

blugnu/time

A simple and lightweight module for Go providing a context clock and a mock clock for testing time-based scenarios in accelerated, deterministic time.

Features

  • Context Clock: A clock that can be passed in a context;

  • Mock Clock: A clock that can be used in tests to simulate time passing independently of the actual time, allowing for accelerated and deterministic testing of time-based code;

  • Mock Timers: Context deadlines, timeouts, timers and tickers that behave deterministically with a mock clock, allowing for testing of time-based code without relying on the system clock or the passage of real time;

  • Compatible: Works as a drop-in replacement for the standard library time package, easing migration to blugnu/time. Clock-agnostic types & functions are aliased, while clock-dependent operations have context-aware alternatives;

  • Lightweight: No external dependencies, making it easy to use and integrate into existing projects;

Installation

go get github.com/blugnu/time

Usage

As far as possible, blugnu/time is designed to be a drop-in replacement for the standard library time package with additional functions where required.

Migration From Standard Library

Migration from the standard library time package to blugnu/time involves replacing references to the time package with references to a blugnu/time.Clock interface, usually obtained from a context:

    import "time"

    func DoSomethingTimeDependent(ctx context.Context) {
        ux := time.Now()
        // ...
    }

becomes:

    import "github.com/blugnu/time"

    func DoSomethingTimeDependent(ctx context.Context) {
        time := time.FromContext(ctx)

        ux := time.Now()
        // ...
    }

Note that shadowing the time package can be a quick way to migrate code that uses the standard library time package to use the blugnu/time package. However, this may upset some linters and could cause confusion in larger codebases. If this is a concern, an alternative name can be used for the clock variable, although this will require more changes to migrate the codebase:

    import "github.com/blugnu/time"

    func DoSomethingTimeDependent(ctx context.Context) {
        clock := time.FromContext(ctx)

        ux := clock.Now()
        // ...
    }

Alternatively, functions are provided in the blugnu/time package that correspond to the standard library time package functions, with the addition of requiring a context:

    import "github.com/blugnu/time"

    func DoSomethingTimeDependent(ctx context.Context) {
        ux := time.Now(ctx)
        // ...
    }
Clock-Independent Usage

Aliases are provided for constants, types and clock-agnostic functions from the standard library time package:

      // standard library time
      import "time"
      ux := time.Unix()

      // becomes:
      import "github.com/blugnu/time"
      ux := time.Unix()
Clock-Dependent Functions

Clock-dependent functions are replaced by similes which accept a context, or may be called using an implementation provided by a clock:

      // standard library time
      import "time"
      time.Now()
      
      // becomes
      import "github.com/blugnu/time"
      time.Now(ctx)

      // or:
      clock := time.ClockFromContext(ctx)
      clock.Now()

Update references to clock-dependent functions to avoid mixing use of mocked and non-mocked time which would cause unpredictable behaviour in tests.

Context Deadlines and Timeouts

Context deadlines and timeouts are clock-dependent. The blugnu/time package provides ContextWithDeadline and ContextWithTimeout functions that return a context with a deadline or timeout that is based on the clock passed in the context. When using a mock clock, the deadline or timeout will be based on the mock clock, allowing for deterministic behaviour in tests.

      // standard library time
      import "time"
      ctx, cancel := context.WithDeadline(parentCtx, time.Now().Add(5*time.Second))
      defer cancel()

      // becomes
      import "github.com/blugnu/time"
      ctx, cancel := time.ContextWithDeadline(parentCtx, time.Now().Add(5*time.Second))
      defer cancel()
In Tests
  • inject a MockClock into the Context used for tests;

  • use the provided MockClock methods to advance the clock in a deterministic fashion to exercise time-dependent code, including context deadlines and timeouts independently of the elapsed time of the test.

Example
// Simulates testing some code using a context with a timeout that would
// normally take 10 seconds to complete in real-time.
// 
// The test will instead run in milliseconds.
func TestAcceleratedTime() {
  // create a mock clock
  clock := time.NewMockClock()

  // create a context with a 10s timeout
  ctx, cancel := clock.ContextWithTimeout(context.Background(), 10*time.Second)
  defer cancel() // ensure the context is cancelled to avoid leaks

  // start a goroutine that will block until the context is cancelled;
  // a waitgroup is used to sync with the test
  var wg sync.WaitGroup
  wg.Add(1)
  go func() {
    <-ctx.Done()
    wg.Done()
  }()

  // advance the mock clock by 10s; this will cause the context to be cancelled
  // immediately and the goroutine to unblock
  clock.AdvanceBy(10 * time.Second)
  wg.Wait()

  // verify that the context was cancelled due to the timeout
  if ctx.Err() != context.DeadlineExceeded {
    t.Errorf("expected context.DeadlineExceeded, got %s", ctx.Err())
  }
}
Additional Functions

Functions are provided for adding or retrieving a clock to/from a context as well as initialising a mock clock either stand-alone or in a context:

    // returns the clock from the context or the system clock if not present
    ClockFromContext(ctx context.Context) Clock

    // adds a clock to the context; panics if the context already has a clock
    ContextWithClock(ctx context.Context, clock Clock) context.Context

    // adds a mock clock to the context; panics if the context already has a clock
    ContextWithMockClock(ctx context.Context, opts ...MockClockOption) (context.Context, MockClock)

    // configures a new mock clock
    NewMockClock(opts ...MockClockOption) Clock

    // returns the clock from the context or nil if not present
    TryClockFromContext(ctx context.Context) Clock

System Clock vs Mock Clocks

The system clock is the actual clock of the system, which is used to measure real time. There is only one system clock.

A mock clock is a simulated clock that can be used to control the passage of time in tests. A mock clock can be used to simulate time passing at a different rate than the system clock while preserving the behaviour of tickers, timers, timeouts and deadlines.

This can provide tests that run more reliably and more quickly than in real-time. For example, a test that requires many hours of elapsed clock time can be executed in milliseconds.

Individual tests may use different mock clocks, allowing for different tests to run at different rates or to simulate different clock behaviours.

💡 A mocked clock in a test is only effective if the code being tested is "context-clock aware". It must consistently use a clock obtained from context and/or use the blugnu/time package functions that accept a context.

Running vs Stopped Clock

A mock clock can be either running or stopped. Mock clocks are created stopped by default, unless the StartRunning() option is applied.

Stopped Clocks

A stopped clock will not advance time automatically. The clock must be explicitly advanced using the AdvanceBy or AdvanceTo methods. This provides precise control over the passage of time in tests.

Running Clocks

When a mock clock is running, it will advance time automatically in real-time whenever a clock operation is performed involving the current time, or the Update method called.

💡 A running mock clock does not update in the background. The "running" state means that the clock advances in real-time only when it is interacted with and it cannot be explicitly advanced by arbitrary increments (AdvanceBy or AdvanceTo).

Attempting to explicitly advance a running clock will result in a panic. This is to prevent accidental use of a running clock in tests that expect a stopped clock.

Similarly, calling Update on a stopped clock will also result in a panic.

Stopping and Starting (a Running Clock)

Although not usually necessary or recommended, a running mock clock may be stopped and started using the Stop and Start methods. Every call to Stop must be matched with a call to Start to resume running.

Attempting to Start a clock that is already running will result in a panic.

Sleeping

Sleeping a mocked clock will block the calling goroutine until the mock time has advanced by the specified duration.

For a running clock, this is handled by waiting for the specified duration using the system clock.

For a stopped clock, the calling goroutine will be suspended until the mock clock has been advanced by the specified duration. Since the caller is suspended, the clock must be advanced by some other goroutine to resume the caller.

Mock Clock Options

time.AtNow

The AtNow option is a convenience for time.AtTime(time.SystemClock().Now()).

time.AtTime

The AtTime option allows you to set the initial time of the mock clock. By default a mock clock is set to the zero time (Unix Epoch).

time.DropsTicks

The DropsTicks option sets the mock clock to drop any extra ticks when advancing time. This option only affects tickers, not timers or context deadlines.

By default, if a ticker is set to fire every 1s and the clock is advanced by 10s, then the ticker will fire 10 times, once for each second. With DropsTicks set the ticker will fire only once in this situation, at the end of the 10 seconds.

time.InLocation

The InLocation option allows you to set the location of the mock clock. The default is UTC.

time.StartRunning

The StartRunning option sets the mock clock to start running immediately when it is created. By default, the mock clock is stopped and must be started manually if required.

time.YieldTime

The mock clock suspends the calling goroutine for 1ms when performing certain operations, allowing goroutines to be scheduled if required.

💡 This is not always necessary, but avoids having to manually yield the goroutine in tests that may otherwise block indefinitely and involves negligible overhead for tests that do not require it.

The YieldTime option allows the time for which the caller is suspended to be changed or disabled entirely (specifying a duration of 0) if required.

Documentation

Index

Examples

Constants

View Source
const (
	// durations
	Day         = time.Hour * 24
	Hour        = time.Hour
	Microsecond = time.Microsecond
	Millisecond = time.Millisecond
	Minute      = time.Minute
	Nanosecond  = time.Nanosecond
	Second      = time.Second
	Week        = time.Hour * 24 * 7

	// date/time formats
	Layout = time.Layout // The reference time, in numerical order

	ANSIC       = time.ANSIC
	DateOnly    = time.DateOnly
	DateTime    = time.DateTime
	RFC822      = time.RFC822
	RFC822Z     = time.RFC822Z // RFC822 with numeric zone
	RFC850      = time.RFC850
	RFC1123     = time.RFC1123
	RFC1123Z    = time.RFC1123Z // RFC1123 with numeric zone
	RFC3339     = time.RFC3339
	RFC3339Nano = time.RFC3339Nano
	Kitchen     = time.Kitchen
	RubyDate    = time.RubyDate
	Stamp       = time.Stamp
	StampMilli  = time.StampMilli
	StampMicro  = time.StampMicro
	StampNano   = time.StampNano
	TimeOnly    = time.TimeOnly
	UnixDate    = time.UnixDate
)

Variables

View Source
var (
	ErrClockAlreadyExists = errors.New("clock already exists")

	ErrClockIsRunning  = internal.ErrClockIsRunning
	ErrClockNotRunning = internal.ErrClockNotRunning
	ErrNotADelorean    = internal.ErrNotADelorean
)
View Source
var (
	Date            = time.Date
	FixedZone       = time.FixedZone
	Parse           = time.Parse
	ParseDuration   = time.ParseDuration
	ParseInLocation = time.ParseInLocation
	Unix            = time.Unix
	UnixMicro       = time.UnixMicro
	UnixMilli       = time.UnixMilli

	UTC = time.UTC
)

Functions

func After added in v0.2.0

func After(ctx context.Context, d Duration) <-chan time.Time

After waits for the duration to elapse and then sends the current time on the returned channel. It is equivalent to NewTimer(d).C.

Mock Clocks

If the context contains a MockClock, the channel will not receive a time value until the clock is advanced by at least the specified duration from its current time.

Note that a running MockClock does not advance automatically; it must be advanced by calling [MockClock.Update] or other method which updates the clock after the required duration has elapsed in real-time. i.e. Any goroutines waiting on the channel returned by After will effectively be blocked in real-time, despite using a MockClock.

GODEBUG asynctimerchan=1

The GODEBUG setting asynctimerchan=1 restores pre-Go 1.23 behaviors when using SystemClock. MockClock does not reproduce those behaviors and using a MockClock with this GODEBUG setting is not supported.

For more information, refer to the standard library time.After documentation.

func ContextWithClock

func ContextWithClock(ctx context.Context, c Clock) context.Context

ContextWithClock returns a new context containing a given clock.

  • if the context already contains a clock the function panics with ErrClockAlreadyExists
  • if the specified Clock is nil, a new context is returned with the SystemClock

func ContextWithDeadline

func ContextWithDeadline(ctx context.Context, t time.Time) (context.Context, context.CancelFunc)

ContextWithDeadline returns a new context with the given deadline. If the given time is in the past, the returned context is already done.

The deadline is set using the clock in the given context. If there is no clock in the context the system clock is used and the result is the same as calling context.WithDeadline.

If the context contains a mock clock, the deadline will expire when that mock clock is advanced to the deadline or later.

func ContextWithDeadlineCause

func ContextWithDeadlineCause(ctx context.Context, t time.Time, cause error) (context.Context, context.CancelFunc)

ContextWithDeadlineCause returns a new context with the given deadline and cause. If the given time is in the past, the returned context is already done.

The cause is used to set the context error.

The deadline is set using the clock in the given context. If there is no clock in the context the system clock is used and the result is the same as calling context.WithDeadlineCause.

If the context contains a mock clock, the deadline will expire when that mock clock is advanced to the deadline or later.

func ContextWithTimeout

func ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc)

ContextWithTimeout returns a new context with the given timeout. If the given duration is zero or negative, the returned context is already done.

The timeout is set using the clock in the given context. If there is no clock in the context the system clock is used and the result is the same as calling context.WithTimeout.

If the context contains a mock clock, the timeout will expire when that mock clock is advanced by at least the given duration from its current time.

func ContextWithTimeoutCause

func ContextWithTimeoutCause(ctx context.Context, d time.Duration, cause error) (context.Context, context.CancelFunc)

ContextWithTimeoutCause returns a new context with the given timeout and cause. If the given duration is zero or negative, the returned context is already done.

The cause is used to set the context error.

The timeout is set using the clock in the given context. If there is no clock in the context the system clock is used and the result is the same as calling context.WithTimeoutCause.

If the context contains a mock clock, the timeout will expire when that mock clock is advanced by at least the given duration from its current time. The cause is used to set the context error.

func Dur added in v0.2.0

func Dur(f func()) time.Duration

Dur returns the duration taken to execute the function f. It uses the SystemClock to measure the duration.

func Sleep

func Sleep(ctx context.Context, d Duration)

Sleep suspends the calling goroutine for the duration specified.

Mock Clocks

If the context holds a MockClock, the calling goroutine is suspended until the clock has been advanced by at least the specified duration. The MockClock must be advanced by a goroutine other than the one calling Sleep.

Note that a running MockClock does not advance automatically; it must be advanced by calling [MockClock.Update] or other method which updates the clock after the required duration has elapsed in real-time. i.e. Any goroutines waiting on a Sleep call will effectively be blocked in real-time, despite using a MockClock.

func Tick

func Tick(ctx context.Context, d Duration) <-chan Time

Tick returns a channel that will send the current time after each tick. If the duration d is zero or negative, Tick will return a nil channel and will not panic.

Efficiency concerns relating to the Tick function prior to Go 1.23 are not significant since the blugnu/time package requires at least Go 1.23.

Types

type Clock

type Clock = internal.Clock

Clock represents an interface described by the functions in the time package of the standard library. It extends the time package with additional methods to create contexts with deadlines and timeouts based on the clock providing the interface.

This allows for the creation of mock clocks for testing purposes through an API that is similar to and consistent with that of the system clock in the standard library `time` package.

func FromContext added in v0.2.0

func FromContext(ctx context.Context) Clock

FromContext returns the Clock in the given context. This function always returns a Clock; if no Clock is in the context, the SystemClock is returned.

func SystemClock

func SystemClock() Clock

SystemClock returns a clock implementation that uses the `time` package functions of the standard library. A variable initialised with SystemClock can be used to access the system clock functions using function that are identical to those provided by standard library time package:

sys := time.SystemClock()
now := sys.Now()
sys.Sleep(2 * time.Second)
ticker := sys.NewTicker(1 * time.Second)

To migrate applications from using the standard time package to this package, replace time package references to an appropriate Clock reference:

Before:

	import "time"

	func CreateUser(ctx context.Context) {
	    user := &User{
	        CreatedAt: time.Now(),
	    }
	    ...
}

After:

	import "github.com/blugnu/time"

	func CreateUser(ctx context.Context) {
	    time := time.FromContext(ctx)
	    user := &User{
	        CreatedAt: time.Now(),
	    }
	    ...
}

Note: the `time` package is shadowed by the `time` variable in the above example.

This minimises the code changes required to migrate a function but may cause
problems or confusion.  Using an alternative variable name avoids this but
will require more changes to the code when migrating.

func TryFromContext added in v0.2.0

func TryFromContext(ctx context.Context) Clock

TryFromContext returns the Clock in the given context or nil if no Clock is present.

type Duration

type Duration = time.Duration

type Location

type Location = time.Location

type MockClock

type MockClock interface {
	// MockClock is a mock implementation of the time.Clock interface.
	Clock

	// AdvanceBy moves the current time of the mock clock forward by a
	// specified duration, triggering any timers or tickers that would have
	// been triggered during that passage of time.
	//
	// Calling this method while the clock is running will result in a panic.
	AdvanceBy(d time.Duration)

	// AdvanceTo moves the current time of the mock clock to a specific time,
	// triggering any timers or tickers that would have been triggered during
	// that passage of time.
	//
	// Calling this method while the clock is running will result in a panic.
	AdvanceTo(t time.Time)

	// CreatedAt returns the mocked time at which the clock was started when created.
	CreatedAt() time.Time

	// IsRunning returns true if the clock is in a running state.
	// In this state the clock is advanced by elapsed time whenever Now()
	// is obtained from the clock or when Update() is explicitly called.
	// AdvanceBy() and AdvanceTo() are not supported when the clock is in a
	// running state and will panic.
	//
	// This more closely mimics the behaviour of a real clock but tests using
	// a running clock may be less deterministic and run more slowly than
	// they might.
	IsRunning() bool

	// SinceCreated returns the elapsed mock time since the clock was created.
	// This is the same as calling clock.Since(clock.CreatedAt()).
	SinceCreated() time.Duration

	// Stop stops the clock from advancing automatically.  Every call to
	// Stop() must be matched with a call to Start() to resume automatic
	// advancement.
	//
	// A MockClock is initially created in stopped mode unless the StartRunning
	// option is specified when initialising the clock.
	Stop()

	// Start resumes automatic advancement of the clock.  Every call to
	// Start() must be matched with a call to Stop() to stop automatic
	// advancement.
	//
	// A MockClock is initially created in stopped mode unless the StartRunning
	// option is specified when initialising the clock.  i.e. if the clock
	// is created in stopped mode, an initial call to Start() is required to
	// start the clock.
	Start()

	// Update moves the current time of the mock clock forward by a duration
	// corresponding to the passage of real-time since it was last updated,
	// triggering any timers or tickers that would have been triggered during
	// that passage of time.
	//
	// Calling this method while the clock is stopped will result in a panic.
	Update()
}

MockClock extends the Clock interface with methods to manipulate the current time of the clock. In normal use, the underlying clock time is advanced only when explicitly directed to do so using AdvanceBy() or AdvanceTo() methods; this is "stopped" mode.

When the clock is "running" the current time is advanced semi-automatically by the passage of real-time since the last time the clock was updated. In "running" mode, the clock is advanced any time that Now() is called, or by calling Update().

It is used to simulate the passage of time in tests.

func ContextWithMockClock

func ContextWithMockClock(parent context.Context, opts ...MockClockOption) (context.Context, MockClock)

ContextWithMockClock is a convenience function for creating a context containing a new mock clock initialised with specified options. The function returns the new Context and the MockClock.

If the parent context already has a clock the function panics with ErrClockAlreadyExists.

This function is intended for testing purposes where the calling function is confident that the parent context does not already contain a clock. The test is able to control the simulated passage of time by advancing the mock clock.

func NewMockClock

func NewMockClock(opts ...internal.MockClockOption) MockClock

NewMockClock returns an instance of a mock clock.

The default settings on a new clock are:

  • initial time set to the UNIX epoch (00:00:00 UTC on Thursday, 1 Jan 1970)
  • stopped; advance with AdvanceBy() or AdvanceTo()
  • does not drop ticks
  • sleeps the calling goroutine for 1ms on various operations

When stopped, the clock must be explicitly advanced using AdvanceBy() or AdvanceTo(). When not stopped Update() may be used to advance the clock by the elapsed real-time since the last advancement.

The clock can be customised using the provided options:

  • AtNow() sets the initial time of the mock clock to the current time;

  • AtTime(t time.Time) sets the initial time of the mock clock;

  • DropsTicks() sets the clock to fire tickers only once where multiple ticks would have been triggered by a single advance of the clock

  • WithYield(d time.Duration) sets a duration for which the calling goroutine is suspended before and after each advancement of the clock.

  • StartRunning() sets the mock clock to start in a running state; in the running state the clock is advanced by elapsed time whenever Now() is obtained from the clock or when Update() is explicitly called. AdvanceBy() and AdvanceTo() are not supported in the running state and will panic.

type MockClockOption added in v0.2.0

type MockClockOption = internal.MockClockOption

func AtNow

func AtNow() MockClockOption

AtNow is a convenience for AtTime(time.Now()).

This may be useful for testing purposes when you want to start the clock at the current time whilst retaining the ability to control the advancement of time.

The time is set in the location of the clock.

func AtTime

func AtTime(t time.Time) MockClockOption

AtTime sets the initial time of the mock clock.

This may be useful for testing purposes when you want to start the clock at a particular time whilst retaining the ability to control the advancement of time. The time is set in the location of the clock.

Default

1970-01-01 00:00:00 +0000 UTC (in the location of the clock)

func DropsTicks

func DropsTicks() MockClockOption

DropsTicks sets the mock clock to drop ticks when the clock is advanced. That is, if the clock is advanced by a duration that would ordinarily result in a ticker being triggered more than once, the clock will only trigger a single tick event for the final tick.

Example

When a ticker is set to tick every 300 ms and the clock is advanced by 1s:

  • in normal operation, the ticker will be triggered at 300ms, 600ms and 900ms.

  • with DropsTicks applied, the clock will only send a tick event for the final tick at 900ms.

This may be used to simulate a reader that is reading from a Ticker and failing to "keep up". This is not ideal since it is using the clock to simulate the reader behaviour but may be easier than contriving that reader behaviour in other ways for testing purposes.

Default

not set/disabled

func InLocation

func InLocation(loc *time.Location) MockClockOption

InLocation sets the mock clock to the given location; the time returned by Now() will be in this location.

It is not normally necessary to set the location of the clock but may be useful when you want to start the clock in a particular location whilst retaining the ability to control the advancement of time.

Default

UTC

func StartRunning

func StartRunning() MockClockOption

StartRunning sets the mock clock to start in a running state. In this state the clock is advanced by elapsed time whenever Now() is obtained from the clock or when Update() is explicitly called.

AdvanceBy() and AdvanceTo() are not supported when the clock is in a running state and will panic.

This more closely mimics the behaviour of a real clock but means that tests will run in real-time; this is not recommended for most tests as it will make them run more slowly than they might.

Default

not set / stopped

func YieldTime added in v0.2.0

func YieldTime(d time.Duration) MockClockOption

YieldTime sets a duration for which the calling goroutine will be suspended when performing operations such as advancing the clock or adding a timer or ticker.

This allows other goroutines to be scheduled at times when it may be useful for a test. The duration should rarely need to be changed and should not be set to a value that is too high as this will cause a test to run more slowly than it might.

To disable this behaviour (not recommended) set the duration to 0.

Default

1ms

type Month

type Month = time.Month

A Month specifies a month of the year, from January (1) to December (12)

type ParseError

type ParseError = time.ParseError

type Ticker

type Ticker = internal.Ticker

Ticker represents a ticker.

Usage is identical to the time.Ticker type in the standard library: the time of each "tick" is read from the channel `C` provided on the Ticker.

A ticker created using a MockClock will tick each time the clock is advanced to (or beyond) the next tick time.

If a MockClock is advanced by a duration that is greater than the period of the ticker, ticks will be sent at each interval unless the clock was configured with DropsTicks. In that case, only the final tick will be produced by the Ticker. This may be useful for simulating a tick consumer that is failing to "keep up".

func NewTicker

func NewTicker(ctx context.Context, d Duration) *Ticker

NewTicker creates a new Ticker that will send the current time on its channel after each tick. The duration d must be greater than zero; if d <= 0, NewTicker will panic.

The duration of the Ticker can be modified using the Reset method.

The Ticker will continue ticking until Stop is called on it.

Mock Clocks

If the context contains a MockClock, the ticker tick each time the clock is advanced by an increment of the specified duration from its current time.

Note that a running MockClock does not advance automatically; it must be advanced by calling [MockClock.Update] or other method which updates the clock after the required duration has elapsed in real-time. i.e. Any goroutines waiting on a Ticker with a running MockClock will effectively be blocked in real-time, despite using a MockClock.

GODEBUG asynctimerchan=1

The GODEBUG setting asynctimerchan=1 restores pre-Go 1.23 behaviors when using SystemClock. MockClock does not reproduce those behaviors and using a MockClock with this GODEBUG setting is not supported.

For more information, refer to the standard library time.NewTicker documentation.

Example
package main

import (
	"fmt"
	"math"

	"github.com/blugnu/time"
)

func main() {
	// using the system clock
	clock := time.SystemClock()
	start := clock.Now()

	// create a ticker that ticks every 100ms
	ticker := clock.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	// output the number and time (since starting) of each tick
	n := 0
	go func() {
		for range ticker.C {
			n++
			fmt.Printf("fire %d @ ~%dms\n", n, 10*int(math.Trunc(float64(clock.Since(start).Milliseconds())/10)))
		}
	}()

	// wait for a little over 500ms
	clock.Sleep(510 * time.Millisecond)

}
Output:

fire 1 @ ~100ms
fire 2 @ ~200ms
fire 3 @ ~300ms
fire 4 @ ~400ms
fire 5 @ ~500ms

type Time

type Time = time.Time

func Now

func Now(ctx context.Context) Time

Now returns the current time from the Clock in the given context. If there is no clock in the context, the SystemClock will be used.

Mock Clocks

If the context contains a MockClock, the time returned will be the current mocked time.

If MockClock is running, the time will have advanced by the elapsed time since the clock was last updated, e.g. by a call to Now or [MockClock.Update].

If the MockClock is not running, Now will return the same Time until the clock is advanced by a call to [MockClock.AdvanceBy] or [MockClock.AdvanceTo].

type Timer

type Timer = internal.Timer

Timer represents a timer; it may obtained from the SystemClock() or a mock obtained from a MockClock.

Usage is identical to the time.Timer type in the standard library: the time of the Timer is read from the channel `C` provided which is sent when the timer expires or is reset.

A Timer created from a MockClock will tick when the clock is advanced to (or beyond) the time specified on the Timer.

func AfterFunc

func AfterFunc(ctx context.Context, d Duration, f func()) *Timer

AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns a Timer that can be used to cancel the call using its Stop method. The returned Timer's C field is not used and will be nil.

Mock Clocks

If the context contains a MockClock, the function f will not be called until the clock is advanced by at least the specified duration from its current time.

Note that a running MockClock does not advance automatically; it must be advanced by calling [MockClock.Update] or other method which updates the clock after the required duration has elapsed in real-time. i.e. Any goroutines waiting on a Timer with a running MockClock will effectively be blocked in real-time, despite using a MockClock.

func NewTimer

func NewTimer(ctx context.Context, d Duration) *Timer

NewTimer creates a new Timer that will send the current time on its channel after at least duration d.

Mock Clocks

If the context contains a MockClock, the timer will not be triggered until the clock is advanced by at least the specified duration from its current time.

Note that a running MockClock does not advance automatically; it must be advanced by calling [MockClock.Update] or other method which updates the clock after at least the required duration has elapsed in real-time to trigger the timer. i.e. goroutines waiting on a Timer will effectively be blocked in real-time, despite using a MockClock.

GODEBUG asynctimerchan=1

The GODEBUG setting asynctimerchan=1 restores pre-Go 1.23 behaviors when using SystemClock. MockClock does not reproduce those behaviors and using a MockClock with this GODEBUG setting is not supported.

For more information, refer to the standard library time.NewTimer documentation.

type Weekday

type Weekday = time.Weekday

A Weekday specifies a day of the week, from Sunday (0) to Saturday (6)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL