Bending DateTime in .NET 8 to Test Your Code Better
An update on Mocking DateTime in .NET. Microsoft has finally made an official way to make it hurt less.

I have previously written a post with a similar title (Bending DateTime in .NET to Test Your Code Better). I hope it helped some people using and testing DateTime
in .NET. It was about solving the age-old problem of validating DateTime
values in your tests. You can’t validate the actual time because milliseconds have passed from when the code ran. It’s not a huge problem, but annoying enough to fix. I had an easy solution to this and packaged it up in a simple-to-use library (SimpleDateTimeProvider) to make it easy to implement.
Well with the release of .NET 8, Microsoft has come up with its own (read better) solution for this particular issue. It’s a different solution, so I figured a follow-up was required.
The Updated Solution
We now have an official way to abstract date and time implementations using a new TimeProvider
class. It’s a simple setup, an abstract class, a system-wide implementation of that abstract, and a NuGet package for your tests that allows engineers to mock date and time with a special implementation of the abstract class.
Sounds complicated, but it really isn’t. Below I’ll lay out what it looks like and how to implement it.
The Abstract Class
This a very simplified overview of the methods and properties that are used in the new TimeProvider
. Stripped of the contents of the class, its raw structure looks like this:
public abstract class TimeProvider
{
public DateTimeOffset GetUtcNow()
public DateTimeOffset GetLocalNow()
public long GetTimestamp()
public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp)
public TimeSpan GetElapsedTime(long startingTimestamp)
public long TimestampFrequency
}
For a more detailed view check the TimeProvider.cs on GitHub.
The System Implementation
Again a simplified view but it can also be found in the TimeProvider
file as well, it looks like this:
public abstract class TimeProvider
{
public static TimeProvider System { get; } = new SystemTimeProvider();
private sealed class SystemTimeProvider : TimeProvider
{
internal SystemTimeProvider() : base()
{
}
}
}
The Mock Implementation
Finally, we have the FakeTimeProvider
it’s implemented in an extension library (Microsoft.Extensions.TimeProvider.Testing) for installation in your testing projects. I’ve simplified the implementation again to look like this:
public class FakeTimeProvider : TimeProvider
{
public FakeTimeProvider()
public FakeTimeProvider(DateTimeOffset startDateTime)
public DateTimeOffset Start { get; }
public TimeSpan AutoAdvanceAmount { get; set; }
public override DateTimeOffset GetUtcNow()
public void SetUtcNow(DateTimeOffset value)
public void Advance(TimeSpan delta)
public void SetLocalTimeZone(TimeZoneInfo localTimeZone)
public override TimeZoneInfo LocalTimeZone
public override long TimestampFrequency
public override long GetTimestamp()
public override string ToString()
}
For a more detailed view check the FakeTimeProvider.cs on GitHub.
Bending Date and Time
This is a simple solution and it’s easy to get underway using the providers, simply inject the system time provider as the TimeProvider.System
implementation in your code. If you are using a dependency injection library, you'll know the syntax but follow the same formula.
_ = builder.Services.AddSingleton<TimeProvider.System>();
_ = builder.Services.AddSingleton<ExampleService>();
The next step is to create your class and use that registered TimeProvider
that we just injected as a singleton. Then use the provider to get the DateTimeOffset
values in your class.
public class ExampleService
{
private readonly TimeProvider timeProvider;
public ExampleService(TimeProvider timeProvider)
{
this.dateTimeProvider = dateTimeProvider;
}
public string GetUtcDateTimeOffset()
{
return $"UTC DateTimeOffset is{this.timeProvider.GetUTCNow()}";
}
}
Now since this is .NET 8 we could use the new C# 12 feature, Primary Constructors, to streamline that code above down to this.
public class ExampleService(TimeProvider timeProvider)
{
public string GetUtcDateTimeOffset()
{
return $"UTC DateTimeOffset is {timeProvider.GetUTCNow()}";
}
}
I’m not going to detail this feature any further, if you want to know more you can find 100,000 other posts that are very excited about it. What would be better is to let Nick Chapsas walk you through it.
The whole purpose of this was to allow for testable code. So now that you have your class above, you can inject the FakeTimeProvider
in its place to control the DateTimeOffset
values in your tests. The following example shows how to write a test in XUnit, using Shouldly for assertion.
[Fact]
public void GetUtcDateTimeOffset_ShouldReturn_MockedUtcOffset()
{
// Arrange
var offset = TimeProvider.System.GetUTCNow().AddDays(-5);
var provider = new FakeTimeProvider(offset);
var service = new Service(provider);
// Act
var result = service.GetUtcDateTimeOffset();
// Assert
_ = result.ShouldBeOfType<string>();
result.ShouldBe($"UTC DateTimeOffset is {provider.GetUTCNow()}");
}
Where Can I Find This?
The TimeProvider
changes are documented on the What’s New in .NET 8 page and the real files are published on GitHub.
If you’ve made it this far and still want the old solution….then here you go, it’s all open-sourced on GitHub and the package is published on NuGet. It will still work for .NET 7 and below as well as .NET Framework implementations, however, it is not backward compatible so updating to .NET 8 would require some fixing.
Connect or Support?
If you like this or want to check out my other work, please connect with me on LinkedIn or GitHub. I’d love it if you’d consider supporting me too, all I’ll ever ask for is $1 on GitHub Sponsors or Buy Me a Coffee.