How many times do we naively rely on DateTime.Now for business dates. Yikes, I just reviewed a system that I wrote a while back and I have chained myself to this concept in a very painful way. Now, I am not responsible for this system any longer but I wanted to try and think of a solution to this problem so that I don’t do it again.
Captain Obvious says: “So with time we seem to have two major units that we care about ‘Date’ and ‘Time’.”
Dates are all about a calendar so lets have an ICalendar and times are all about clocks so lets have an IClock too. Now we can have some concrete SystemCalender and SystemClock that basically just wrap the DateTime.Now type functions. The more interesting behavior for your business would be / could be wrapped in a concrete implementation called, wait for it, Business Calendar and BusinessClock.
public interface IClock
{
DateTime Now {get;}
}
public interface ICalendar
{
DateTime Today {get;}
}
Some things that I like about this. I like that this can be database backed, or by a filesystem, or a configuration file. It really becomes less of a concern if I need to change something. If I care more about calendar than clocks I can always use the system clock but then use the business calendar. Really at this point its all about making the choice an explicit choice. Its another one of these small things that can make your system much easier to rerun should a run fail, or just more tolerant of changes in time or what holidays you recognize, etc.
public class SystemClock : IClock
{
public DateTime Now { get { return DateTime.Now; } }
}
public class SystemCalendar : ICalendar
{
public DateTime Today { get{ return DateTime.Today; } }
}
not to abuse extension methods (oh what the hell why not, its fun)
public static class CalendarExtensions
{
public static bool IsHoliday(this ICalendar calendar)
{
return _holidayRepository.Find(calendar.Today).IsNotNull();
}
}
Ok, the code above is way contrived and totally made up but I like how the base calendars don’t have to have every function you may want and can instead focus on the problem of representing dates and times the correct way and that you can bolt on stuff for your app later. Of course you can get yourself into trouble this way as well but sharp tools are nice!
As always leave improvements in the comments!
-d