Represents a synthetic time provider that can be used to enable deterministic behavior in tests.
public class ManualTimeProvider
Inheritance System.TimeProvider 🡒 ManualTimeProvider
Learn more at TimeProviderExtensions on GitHub.
Initializes a new instance of the ManualTimeProvider class.
public ManualTimeProvider();
This creates a provider whose time is initially set to midnight January 1st 2000 and with the local time zone set to System.TimeZoneInfo.Utc. The provider is set to not automatically advance time each time it is read.
Initializes a new instance of the ManualTimeProvider class.
public ManualTimeProvider(System.DateTimeOffset startDateTime, System.TimeZoneInfo localTimeZone);
startDateTime
System.DateTimeOffset
The initial time and date reported by the provider.
localTimeZone
System.TimeZoneInfo
Optional local time zone to use during testing. Defaults to System.TimeZoneInfo.Utc.
The provider is set to not automatically advance time each time it is read.
Initializes a new instance of the ManualTimeProvider class.
public ManualTimeProvider(System.DateTimeOffset startDateTime);
startDateTime
System.DateTimeOffset
The initial time and date reported by the provider.
The local time zone set to System.TimeZoneInfo.Utc. The provider is set to not automatically advance time each time it is read.
Gets the number of active ManualTimer, that have callbacks that are scheduled to be triggered at some point in the future.
public int ActiveTimers { get; }
Gets or sets the auto advance behavior of this ManualTimeProvider.
public TimeProviderExtensions.AutoAdvanceBehavior AutoAdvanceBehavior { get; set; }
Gets the starting date and time for this provider.
public System.DateTimeOffset Start { get; set; }
Gets the amount by which the value from GetTimestamp() increments per second.
public override long TimestampFrequency { get; }
This is fixed to the value of System.TimeSpan.TicksPerSecond.
Advances time by a specific amount.
public void Advance(System.TimeSpan delta);
delta
System.TimeSpan
The amount of time to advance the clock by.
System.ArgumentOutOfRangeException
Thrown if delta is negative. Going back in time is not supported.
Advancing time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.
If advancing time moves it paste multiple scheduled timer callbacks, the current date/time reported by GetUtcNow() at the point when each callback is invoked will match the due time of the callback.
For example:
var start = sut.GetTimestamp();
var timer = manualTimeProvider.CreateTimer(
callback: _ => manualTimeProvider.GetElapsedTime(start),
state: null,
dueTime: Span.FromSecond(1),
period: TimeSpan.FromSecond(1));
manualTimeProvider.Advance(TimeSpan.FromSecond(3));
The call to Advance(TimeSpan.FromSecond(3))
causes the timer
s callback to be invoked three times,
and the result of the manualTimeProvider.GetElapsedTime(start)
in the callback call will be 1 second, 2 seconds,
and 3 seconds. In other words, the time of the provider is set before the time callback is invoked
to the time that the callback is scheduled to be invoked at.
If the desired result is to jump time by delta and then invoke the timer callbacks
the expected number of times, i.e. such that the result of manualTimeProvider.GetElapsedTime(start)
in the callback is
3 seconds, 3 seconds, and 3 seconds, use Jump(DateTimeOffset) or Jump(TimeSpan) instead.
Learn more about this behavior at in the documentation.
Creates an instance of a ManualTimer. This method is called by CreateTimer(TimerCallback, object, TimeSpan, TimeSpan).
protected internal virtual TimeProviderExtensions.ManualTimer CreateManualTimer(System.Threading.TimerCallback callback, object? state, TimeProviderExtensions.ManualTimeProvider timeProvider);
callback
System.Threading.TimerCallback
A delegate representing a method to be executed when the timer fires. The method specified for callback should be reentrant, as it may be invoked simultaneously on two threads if the timer fires again before or while a previous callback is still being handled.
state
System.Object
An object to be passed to the callback. This may be null.
timeProvider
ManualTimeProvider
The ManualTimeProvider which is used to schedule invocations of the callback with.
Override this methods to return a custom implementation of ManualTimer. This also allows for intercepting and wrapping the provided timer callback and state, enabling more advanced testing scenarios.
Creates a new System.Threading.ITimer instance, using System.TimeSpan values to measure time intervals.
public TimeProviderExtensions.ManualTimer CreateTimer(System.Threading.TimerCallback callback, object? state, System.TimeSpan dueTime, System.TimeSpan period);
callback
System.Threading.TimerCallback
A delegate representing a method to be executed when the timer fires. The method specified for callback should be reentrant, as it may be invoked simultaneously on two threads if the timer fires again before or while a previous callback is still being handled.
state
System.Object
An object to be passed to the callback. This may be null.
dueTime
System.TimeSpan
The amount of time to delay before callback is invoked. Specify System.Threading.Timeout.InfiniteTimeSpan to prevent the timer from starting. Specify System.TimeSpan.Zero to start the timer immediately.
period
System.TimeSpan
The time interval between invocations of callback. Specify System.Threading.Timeout.InfiniteTimeSpan to disable periodic signaling.
ManualTimer
The newly created System.Threading.ITimer instance.
System.ArgumentNullException
callback is null.
System.ArgumentOutOfRangeException
The number of milliseconds in the value of dueTime or period is negative and not equal to System.Threading.Timeout.Infinite, or is greater than System.Int32.MaxValue.
The delegate specified by the callback parameter is invoked once after dueTime elapses, and thereafter each time the period time interval elapses.
If dueTime is zero, the callback is invoked immediately. If dueTime is -1 milliseconds, callback is not invoked; the timer is disabled, but can be re-enabled by calling the System.Threading.ITimer.Change(System.TimeSpan,System.TimeSpan) method.
If period is 0 or -1 milliseconds and dueTime is positive, callback is invoked once; the periodic behavior of the timer is disabled, but can be re-enabled using the System.Threading.ITimer.Change(System.TimeSpan,System.TimeSpan) method.
The return System.Threading.ITimer instance will be implicitly rooted while the timer is still scheduled.
CreateTimer(TimerCallback, object, TimeSpan, TimeSpan) captures the System.Threading.ExecutionContext and stores that with the System.Threading.ITimer for use in invoking callback each time it's called. That capture can be suppressed with System.Threading.ExecutionContext.SuppressFlow.
To move time forward for the returned System.Threading.ITimer, call Advance(TimeSpan) or SetUtcNow(DateTimeOffset) on this time provider.
Gets the current high-frequency value designed to measure small time intervals with high accuracy in the timer mechanism.
public override long GetTimestamp();
System.Int64
A long integer representing the high-frequency counter value of the underlying timer mechanism.
This implementation bases timestamp on System.DateTimeOffset.UtcTicks, since the progression of time is represented by the date and time returned from GetUtcNow().
If TimestampAdvanceAmount is greater than System.TimeSpan.Zero, calling this method will move time forward by the amount specified by TimestampAdvanceAmount. The long returned from this method will reflect the timestamp before the auto advance was applied, if any.
Gets a System.DateTimeOffset value whose date and time are set to the current Coordinated Universal Time (UTC) date and time and whose offset is Zero, all according to this ManualTimeProvider's notion of time.
public override System.DateTimeOffset GetUtcNow();
If UtcNowAdvanceAmount is greater than System.TimeSpan.Zero, calling this method will move time forward by the amount specified by UtcNowAdvanceAmount. The System.DateTimeOffset returned from this method will reflect the time before the auto advance was applied, if any.
Jumps the date and time returned by GetUtcNow() to value and triggers any scheduled items that are waiting for time to be forwarded.
public void Jump(System.DateTimeOffset value);
value
System.DateTimeOffset
The new UtcNow time.
System.ArgumentOutOfRangeException
Thrown if value is less than the value returned by GetUtcNow(). Going back in time is not supported.
Jumping time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.
If jumping time moves it paste one or more scheduled timer callbacks, the current date/time reported by GetUtcNow() and GetTimestamp() will match the new date/time based on the value specified in the request.
For example:
var start = sut.GetTimestamp();
var timer = manualTimeProvider.CreateTimer(
callback: _ => manualTimeProvider.GetElapsedTime(start),
state: null,
dueTime: Span.FromSecond(1),
period: TimeSpan.FromSecond(1));
manualTimeProvider.Jump(manualTimeProvider.Start + TimeSpan.FromSecond(3));
The call to Jump(manualTimeProvider.Start + TimeSpan.FromSecond(3))
causes the timer
s callback to be invoked three times,
and the result of the manualTimeProvider.GetElapsedTime(start)
in the callback call will be 3 seconds
during all three invocations.
If the desired result is that timer callbacks happens exactly at their scheduled callback time, i.e. such that the result
of manualTimeProvider.GetElapsedTime(start)
in the callback will be 1 second, 2 seconds, and 3 seconds,
use Advance(TimeSpan) or SetUtcNow(DateTimeOffset) instead.
Learn more about this behavior at in the documentation. ///
Jumps time by a specific amount.
public void Jump(System.TimeSpan delta);
delta
System.TimeSpan
The amount of time to jump the clock by.
System.ArgumentOutOfRangeException
Thrown if delta is negative. Going back in time is not supported.
Jumping time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.
If jumping time moves it paste one or more scheduled timer callbacks, the current date/time reported by GetUtcNow() and GetTimestamp() will match the new date/time based on the delta specified in the request.
For example:
var start = sut.GetTimestamp();
var timer = manualTimeProvider.CreateTimer(
callback: _ => manualTimeProvider.GetElapsedTime(start),
state: null,
dueTime: Span.FromSecond(1),
period: TimeSpan.FromSecond(1));
manualTimeProvider.Jump(TimeSpan.FromSecond(3));
The call to Jump(TimeSpan.FromSecond(3))
causes the timer
s callback to be invoked three times,
and the result of the manualTimeProvider.GetElapsedTime(start)
in the callback call will be 3 seconds
during all three invocations.
If the desired result is that timer callbacks happens exactly at their scheduled callback time, i.e. such that the result
of manualTimeProvider.GetElapsedTime(start)
in the callback will be 1 second, 2 seconds, and 3 seconds,
use Advance(TimeSpan) or SetUtcNow(DateTimeOffset) instead.
Learn more about this behavior at in the documentation. ///
Sets the local time zone.
public void SetLocalTimeZone(System.TimeZoneInfo localTimeZone);
localTimeZone
System.TimeZoneInfo
The local time zone.
Sets the date and time returned by GetUtcNow() to value and triggers any scheduled items that are waiting for time to be forwarded.
public void SetUtcNow(System.DateTimeOffset value);
value
System.DateTimeOffset
The new UtcNow time.
System.ArgumentOutOfRangeException
Thrown if value is less than the value returned by GetUtcNow(). Going back in time is not supported.
Setting time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.
If the set time moves it paste multiple scheduled timer callbacks, the current date/time reported by GetUtcNow() at the point when each callback is invoked will match the due time of the callback.
For example:
var start = sut.GetTimestamp();
var timer = manualTimeProvider.CreateTimer(
callback: _ => manualTimeProvider.GetElapsedTime(start),
state: null,
dueTime: Span.FromSecond(1),
period: TimeSpan.FromSecond(1));
manualTimeProvider.SetUtcNow(manualTimeProvider.Start + TimeSpan.FromSecond(3));
The call to SetUtcNow(manualTimeProvider.Start + TimeSpan.FromSecond(3))
causes the timer
s callback to be invoked three times,
and the result of the manualTimeProvider.GetElapsedTime(start)
in the callback call will be 1 second, 2 seconds,
and 3 seconds. In other words, the time of the provider is set before the time callback is invoked
to the time that the callback is scheduled to be invoked at.
If the desired result is to jump to the time specified in value and then invoke the timer callbacks
the expected number of times, i.e. such that the result of manualTimeProvider.GetElapsedTime(start)
in the callback is
3 seconds, 3 seconds, and 3 seconds, use Jump(DateTimeOffset) or Jump(TimeSpan) instead.
Learn more about this behavior at in the documentation. ///
Returns a string representation this clock's current time.
public override string ToString();
System.String
A string representing the clock's current time.