You know that feeling when everything compiles, all your unit tests are green, and you’re about to push with confidence… and then suddenly, tests start failing randomly? That was me — confused, frustrated, and convinced I was in a timeline where DateTime.Now
had turned into a prank API.
This is a story about how a small detail — using DateTime.Now
directly — created chaos in my tests and how I fixed it by learning a better way.
The Problem
I was working on some time-sensitive logic — stuff like “expire this thing after 24 hours” or “schedule the next retry in 30 minutes.” Naturally, I reached for DateTime.Now
like any normal developer.
It worked. Locally. Sometimes. Until my unit tests started failing… randomly.
At first, I blamed the CI server. Then time zones. Then cosmic rays. But no — the problem was me. I had written code that depended on the current time, and my tests were running at different times of day, on different machines.
Basically: I was introducing non-deterministic behavior into code that was supposed to be rock-solid.
The Solution
The fix? Abstract the system clock. Instead of calling DateTime.Now
directly, I created a simple interface:
public interface IClock
{
DateTime Now { get; }
}
Then implemented it like this:
public class SystemClock : IClock
{
public DateTime Now => DateTime.Now;
}
In production, I use SystemClock
. In tests, I inject a fake:
public class FakeClock : IClock
{
public DateTime Now { get; set; }
}
Boom — no more flaky tests. I control the time now.
Deeper Explanation
Using DateTime.Now
is tempting because it’s easy. But when you’re writing code that’s supposed to behave consistently, you’re introducing a hidden dependency on real-world time. That makes your tests unreliable, harder to debug, and sometimes impossible to reproduce.
By abstracting time behind an interface, you make your code more testable, more predictable, and — bonus — you might just understand your own logic better too.
Best Practices
- Never use
DateTime.Now
directly in logic or tests - Abstract time using an
IClock
orIDateTimeProvider
interface - Keep time-sensitive logic decoupled from system time
- Always write tests assuming full control over inputs — especially time
- As Microsoft advises: “One principle of a unit test is that it must have full control of the system under test. However, this principle can be problematic when production code includes calls to static references (for example,
DateTime.Now
).”
— Unit testing best practices – Microsoft Docs
Conclusion
So yeah — I used DateTime.Now
, and my tests broke randomly. But now I know better, and so do you. Abstract your clocks, write better tests, and reclaim your sanity.
The future is predictable — if you don’t hardcode the present.
Leave a Reply