Software Development

Behind the scenes

I Used DateTime.Now — and My Tests Broke Randomly

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 or IDateTimeProvider 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

Your email address will not be published. Required fields are marked *

About Me

I’m a software developer sharing thoughts, tips, and lessons from everyday coding life — the good, the bad, and the buggy.