<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr" -->

---
title: TimeProvider and the End of Untestable DateTime.Now
description: DateTime.Now has always been hard to test because it reads the system clock directly with no way to override it, leading teams to hand-roll their own...
canonical: https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: TimeProvider and the End of Untestable DateTime.Now | daily.dev
og:description: DateTime.Now has always been hard to test because it reads the system clock directly with no way to override it, leading teams to hand-roll their own...
og:url: https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr
og:image: https://api.daily.dev/og/posts/nT8roakrR.png
og:image:alt: TimeProvider and the End of Untestable DateTime.Now
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# TimeProvider and the End of Untestable DateTime.Now

**[Maarten Balliauw](https://daily.dev/sources/maartenballiauw)** · 6 min read · 0 upvotes · 0 comments

## Summary

DateTime.Now has always been hard to test because it reads the system clock directly with no way to override it, leading teams to hand-roll their own abstractions like IClock or IDateTimeProvider. Since .NET 8, TimeProvider provides a standard, built-in abstraction in the System namespace for getting the current time, local time, and high-resolution timestamps, plus creating timers. The companion FakeTimeProvider (from the Microsoft.Extensions.TimeProvider.Testing package) lets tests pin or advance the clock deterministically, including firing timer callbacks, without real waiting. Duende IdentityServer v8 adopted TimeProvider in place of its own IClock wrapper as part of a breaking change release.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.maartenballiauw.be/posts/2026-07-22-timeprovider-and-the-end-of-untestable-datetime-now>

## Questions this post answers

### How do I make code that uses DateTime.Now testable in .NET 8?

Inject the TimeProvider abstract class from the System namespace instead of calling DateTime.UtcNow or DateTimeOffset.UtcNow directly. Register TimeProvider.System as a singleton in production, and call GetUtcNow(), GetLocalNow(), or GetTimestamp() through the injected instance. In tests, swap in Microsoft.Extensions.Time.Testing's FakeTimeProvider to control the clock.

_daily.dev surfaces practical .NET testing patterns like this for developers hardening time-dependent logic._

### How do I advance time in a FakeTimeProvider test without using Thread.Sleep?

Call Advance(TimeSpan delta) on a FakeTimeProvider instance to move its clock forward by a specific amount, or SetUtcNow(DateTimeOffset) to jump to an exact moment. Both trigger any pending timers whose due time falls within the advanced range, making logic like cache expiry, retry back-off, and sliding windows testable at full speed with no real waiting.

_developers chasing flaky time-based tests can keep up with .NET testing techniques via daily.dev._

### What NuGet package provides FakeTimeProvider for testing in .NET?

FakeTimeProvider ships in the Microsoft.Extensions.TimeProvider.Testing NuGet package, separate from the core TimeProvider abstract class that lives in the base class library's System namespace. It can be constructed with a fixed starting DateTimeOffset or left to default, and implements the same TimeProvider contract so it can be injected anywhere a TimeProvider is expected.

_teams picking testing libraries for .NET time logic can track package choices like this on daily.dev._

## Similar posts on daily.dev

- [Stop Pretending TimeProvider Doesn't Exist — Daily DevOps & .NET](https://daily.dev/posts/stop-pretending-timeprovider-doesn-t-exist-daily-devops-net-8lez0ga1i) · We Are .NET · 21 upvotes · 1 comments
- [TimeProvider and FakeTimeProvider in .NET Tests](https://daily.dev/posts/timeprovider-and-faketimeprovider-in-net-tests-cpo0lbau7) · Milan Jovanović · 20 upvotes · 1 comments
- [TimeProvider Test Patterns That Hold Up in CI and Production — Daily DevOps & .NET](https://daily.dev/posts/timeprovider-test-patterns-that-hold-up-in-ci-and-production-daily-devops-net-ebwurnbxn) · Daily DevOps & .NET · 8 upvotes · 0 comments
- [Time in C\+\+: Once More About Testing](https://daily.dev/posts/time-in-c-once-more-about-testing-wm0vdb66u) · Sandor Dargo · 0 upvotes · 0 comments
- [Time is a construct but it can still break your software](https://daily.dev/posts/time-is-a-construct-but-it-can-still-break-your-software-bfsxtqo37) · Stack Overflow Blog · 2 upvotes · 0 comments

---

Tags: [#testing](https://daily.dev/tags/testing), [#.net](https://daily.dev/tags/.net), [#c#](https://daily.dev/tags/c#), [#dependency-injection](https://daily.dev/tags/dependency-injection)

[View this post on daily.dev](https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"TimeProvider and the End of Untestable DateTime.Now","url":"https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr"},"datePublished":"2026-10-04T13:04:08.609Z","dateModified":"2026-10-04T13:04:45.060Z","description":"DateTime.Now has always been hard to test because it reads the system clock directly with no way to override it, leading teams to hand-roll their own...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/988c29c5b660e262eedbba3695b28ce3?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/988c29c5b660e262eedbba3695b28ce3?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Maarten Balliauw","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Maarten Balliauw","logo":"https://media.daily.dev/image/upload/s--rOTg3VYO--/f_auto,q_auto/v1791119043/logos/maartenballiauw?_a=BAMAMicg0","url":"https://daily.dev/sources/maartenballiauw"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"testing,.net,c#,dependency-injection","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Maarten Balliauw","item":"https://daily.dev/sources/maartenballiauw"},{"@type":"ListItem","position":3,"name":"TimeProvider and the End of Untestable DateTime.Now"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/timeprovider-and-the-end-of-untestable-datetime-now-nt8roakrr#faq","mainEntity":[{"@type":"Question","name":"How do I make code that uses DateTime.Now testable in .NET 8?","acceptedAnswer":{"@type":"Answer","text":"Inject the TimeProvider abstract class from the System namespace instead of calling DateTime.UtcNow or DateTimeOffset.UtcNow directly. Register TimeProvider.System as a singleton in production, and call GetUtcNow(), GetLocalNow(), or GetTimestamp() through the injected instance. In tests, swap in Microsoft.Extensions.Time.Testing's FakeTimeProvider to control the clock. daily.dev surfaces practical .NET testing patterns like this for developers hardening time-dependent logic."}},{"@type":"Question","name":"How do I advance time in a FakeTimeProvider test without using Thread.Sleep?","acceptedAnswer":{"@type":"Answer","text":"Call Advance(TimeSpan delta) on a FakeTimeProvider instance to move its clock forward by a specific amount, or SetUtcNow(DateTimeOffset) to jump to an exact moment. Both trigger any pending timers whose due time falls within the advanced range, making logic like cache expiry, retry back-off, and sliding windows testable at full speed with no real waiting. developers chasing flaky time-based tests can keep up with .NET testing techniques via daily.dev."}},{"@type":"Question","name":"What NuGet package provides FakeTimeProvider for testing in .NET?","acceptedAnswer":{"@type":"Answer","text":"FakeTimeProvider ships in the Microsoft.Extensions.TimeProvider.Testing NuGet package, separate from the core TimeProvider abstract class that lives in the base class library's System namespace. It can be constructed with a fixed starting DateTimeOffset or left to default, and implements the same TimeProvider contract so it can be injected anywhere a TimeProvider is expected. teams picking testing libraries for .NET time logic can track package choices like this on daily.dev."}}]}
```

