var startDateTime = new DateTimeOffset( 2021, 01, 01, 00, 00, 00, TimeSpan.Zero );
var endDateTime = startDateTime.AddMinutes( 1 );
var clock = new FakeClock { UtcNow = new DateTimeOffset( 2021, 01, 01, 00, 00, 00, TimeSpan.Zero ) };
var foo = new Foo( clock, TimeSpan.FromMilliseconds( 500 ) )
while ( clock.UtcNow < endDateTime )
var timeSpan = TimeSpan.FromMilliseconds( 500 + Random.Shared.Next( 5, 50 ) );
clock.UtcNow += timeSpan;
Console.WriteLine( "[{0:hh:mm:ss.ffffff}] {1} ({2})", clock.UtcNow, foo.Distance, slices );
DateTimeOffset UtcNow { get; }
class RealTimeClock : ISystemClock
public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
class FakeClock : ISystemClock
public DateTimeOffset UtcNow { get; set; } = DateTimeOffset.UtcNow;
private DateTimeOffset _lastTick;
public Foo( ISystemClock systemClock, TimeSpan slice )
SystemClock = systemClock;
public bool IsRunning { get; private set; }
public double ActualSpeed { get; set; }
public double Distance { get; private set; }
public ISystemClock SystemClock { get; }
public TimeSpan Slice { get; }
if ( !IsRunning ) return 0;
var now = SystemClock.UtcNow;
var duration = now - _lastTick;
if (duration < Slice) return 0;
var slices = Convert.ToInt32( duration.TotalMilliseconds / Slice.TotalMilliseconds );
var consumedDuration = slices * Slice;
_lastTick = now - ( duration - consumedDuration );
Distance += ActualSpeed / TimeSpan.FromMinutes( 1 ).TotalMilliseconds * slices * Slice.TotalMilliseconds;
_lastTick = SystemClock.UtcNow;
if ( !IsRunning ) return;