extensions icon indicating copy to clipboard operation
extensions copied to clipboard

[API Proposal]: FakeTimeProvider, option to allow going backwards

Open jjxtra opened this issue 1 year ago • 7 comments

Background and motivation

I'm using reflection to get around FakeTimeProvider inability to go backwards. Would be nice if a bool could be added to allow setting time earlier.

Thanks for considering.

API Proposal


public sealed class FakeTimeProvider : TimeProvider
{
    public bool AllowBackwardsTimeProgression { get; set; }
}

API Usage

// Fancy the value
FakeTimeProvider t = ...
t.AllowBackwardsTimeProgression = true;
t.SetUtcNow(new DateTimeOffset(1990, 1, 1, 1, 1, 1));
t.SetUtcNow(new DateTimeOffset(1984, 1, 1, 1, 1, 1));

Alternative Designs

No response

Risks

None I can think of. This new property will default to false.

jjxtra avatar Mar 29 '24 12:03 jjxtra

@stephentoub I presume it's possible for the normal time provider's idea of current time to move backwards? And this presumably doesn't affect any outstanding timers (since they are created with relative time), and presumably wouldn't affect the value returned by GetTimestamp?

geeknoid avatar Apr 02 '24 20:04 geeknoid

The internal property storing the time for FakeTimeProvider is called _now and is simply a DateTimeOffset value.

jjxtra avatar Apr 02 '24 21:04 jjxtra

If this is for testing how your application would react to a server administrator abruptly setting the clock -- then I think the method should also support setting a future wall-clock time without affecting elapsed time.

var fake = new FakeTimeProvider(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero));
long startStamp = fake.GetTimestamp();

// simulate 1 second passing
fake.Advance(TimeSpan.FromSeconds(1));
Debug.Assert(fake.GetElapsedTime(startStamp) == TimeSpan.FromSeconds(1));

// simulate 59 more seconds passing
fake.SetUtcNow(new DateTimeOffset(1970, 1, 1, 0, 1, 0, TimeSpan.Zero));
Debug.Assert(fake.GetElapsedTime(startStamp) == TimeSpan.FromMinutes(1));

// NEW: simulate an administrator setting the clock forward
// no effect on elapsed time
fake.SetUtcNow(new DateTimeOffset(1970, 1, 1, 0, 2, 0, TimeSpan.Zero), abrupt: true);
Debug.Assert(fake.GetElapsedTime(startStamp) == TimeSpan.FromMinutes(1));

// simulate 60 more seconds passing
fake.SetUtcNow(new DateTimeOffset(1970, 1, 1, 0, 3, 0, TimeSpan.Zero));
Debug.Assert(fake.GetElapsedTime(startStamp) == TimeSpan.FromMinutes(2));

// NEW: simulate an administrator setting the clock backward
// no effect on elapsed time
fake.SetUtcNow(new DateTimeOffset(1970, 1, 1, 0, 2, 50, TimeSpan.Zero), abrupt: true); 
Debug.Assert(fake.GetElapsedTime(startStamp) == TimeSpan.FromMinutes(2));

KalleOlaviNiemitalo avatar Apr 03 '24 13:04 KalleOlaviNiemitalo

@stephentoub I presume it's possible for the normal time provider's idea of current time to move backwards? And this presumably doesn't affect any outstanding timers (since they are created with relative time), and presumably wouldn't affect the value returned by GetTimestamp?

Should be fine. If we find some place it's not, I'd consider that a bug.

stephentoub avatar Apr 04 '24 21:04 stephentoub

@geeknoid -can this issue be closed as fixed by https://github.com/dotnet/extensions/pull/5192 ?

evgenyfedorov2 avatar Jul 23 '24 08:07 evgenyfedorov2

The AdjustTime method still has an ExperimentalAttribute. Are issues in this repository usually closed before APIs are reviewed and declared stable?

KalleOlaviNiemitalo avatar Jul 23 '24 10:07 KalleOlaviNiemitalo

@evgenyfedorov2 We need an API review to approve the new API, so we can remove the experimental attribute, and then we can close this issue.

geeknoid avatar Jul 23 '24 17:07 geeknoid

I've sent a request to API Review Board for a review, so we can go out of experimental stage for that method.

amadeuszl avatar Feb 17 '25 15:02 amadeuszl