samedi 16 juin 2018

Programming with dates is hard

Time and date is not a trivial problem in programming. You can expect different precision, handle different timezones and different format when you convert them from and to a string.

You may remember some issues related to date that appended in the IT world. Take Y2K, that obliged companies to check and fix the way they handled date in their program before the millennium. I guess it's been a costly procedure in some of the case in term of research, fix and testing. For non tech people though, it's a ridiculous case: in our daily life, we use time and dates casually without thinking about it.

Another sign that handling dates is not trivial: the plethora of library available. In Python, the standard module datetime does not handle time zones, so we have pytz. But as it's not human friendly, everyone got to use Arrow. Then Pendulum came out, claiming that arrow got it wrong and it became the new standard for community. Meanwhile, Kenneth Reitz (requests, pipenv,…) released Maya to do the same thing. Help, we're lost!

It's not specific to Python. In Java, Joda-Time has been the preferred library to handle dates, rather than the standard library. Then Java 8 came out with a new java.time package that can be used instead of Joda. I worked recently in a code base that mixed both libraries. It inspired me this post.

On the other hand, when you have chosen a library, getting the current date is super simple, using a call like mytimelib.today(). Cool. How about testing then?

Actual time does not belong in your system, it's a dependency, bound to the real world. If your business domain relies on date for some sort, you may avoid to use your date library directly.

When I need to integrate business logic based on date, I use my own Date and Calendar classes which allows me to:

  • Get the precision I want for comparison. For instance, my domain can rely on lapsing dates with month precision and I don't need more.
  • Have a reference implementation. My dates can be created from instances created with different date libs.
  • Get default formats for date as String
  • Create a fake calendar for testing that gives me control on current date generation. So I do not need to scratch my head when I have to compare dates in tests.

In the past I worked on a project for an insurance company. We naively used mylib.today() calls all over the place. When the main features were implemented and tested, business people told us that they wanted to test the system behaviour when contracts get on term. To do so they wanted to be able to alter system current date.

Guess who replaced all the calls by injecting a custom Calendar and provided a service endpoint that allow users to modify the current date for testing…

So pay attention to your business domain. If it relies on dates in some sort, you'd better treat them as an external dependency. Then you'll be able to use the lib you want, and even to change it seemlessly if it get oldfashionned.