Date and Time is one of those frustrating things in building an application that can be difficult to get right.

  • Ensuring that you can capture your domain accurately across timezones.
  • Forgotting that your API can be hosted in UTC, i.e. different to your local machine.
    • Side Note: This is why it's important to always test in a deployed environment before handing over for testing or the Product Owner for sign-off.
  • Allowing your code to be testable, i.e. date sensitive business rules

I have previously tried to solve the last point using a IClock or ITimeProvider interfaces. A few years ago, I rolled up my experiences from several projects into a library DateTimeProvider.

In my (humble) opinion, DateTimeProvider has a few great features:

  • Uses static injection that you can access DateTimeProvider.Now from anywhere in your code similar to DateTime.Now. I prefer this approach so that you aren't forced to dependency inject an instance of IClock or IDateTimeProvider down through layers.

  • It allows you to Pin DateTime so can be manipulated in a fixed scope. An example below:

    I think this is a really useful feature as it allows to you to write and test time dependent code.

  • Finally, it has a Rosyln Analyser that detects usages of DateTime.Now and in Visual Studio suggests replacing usages :lightbulb: with DateTimeProvider.

One caveat of using a static implementation is that you need to async theadsafe or otherwise this will happen.

rick-morty-time-ball-2

This is relatively easier to using AsyncLocal<T> as I'll show you in a bit.

What about Date or Time?

This abstraction works well if your domain only needs DateTime and rough approximations of TimeZone, i.e. most simple applications.

In the application that I'm tech leading, we have non-functional requirements that need precise handling of date and/or time across multiple time-zones. After a bit of research, If you're in a similar situation, I recommend using NodaTime by Jon Skeet - it gives you the much needed confidence that you are capturing date/time correctly.

Using NodaTime

A few weeks after we switched our to using NodaTime, a friend raised issue DateTimeProvider #29 that I should use Noda Time instead.

Learn how to use NodaTime's Instant and the IClock interface which pretty much does what this is trying to do.

I agreed! :+1: Except... that NodaTime prefers the dependency injection method, which as discussed above, I think for a core cross-cutting concern you want to make the usage as easy as possible.

So, let's wrap the Noda's IClock interface in a static provider that is also async thread-safe :ok_hand:.

Happy coding.