Save Time by Doing Time the Right Way With Domain-Driven APIs

We expected just a plain old date, but all of a sudden we get an “instant in time”, with milliseconds and a UTC time zone.

If you look at the documentation a little closer, you’ll notice they even provide formulas for you to calculate a day yourself.

How kind of them!JavaScript is widely known to be funny, but more mature languages surely must have gotten this right.

In Java, a Date is(…) a specific instant in time, with millisecond precision.

Nope, broken as well.

Perhaps .

NET then?DateTime StructThe DateTime value type represents dates and times (…) Time values are measured in 100-nanosecond units called ticks.

A particular date is the number of ticks since 12:00 midnight, January 1, 0001 A.

D.

(C.

E.

)…On the upper side, they gave their type a better name to let us know time is involved as well.

On the Microsoft side, they of course used a starting offset that is different to what everybody else seems to have settled for.

But let’s not miss this little gem over here:DateTime date1 = new DateTime(2008, 6, 1, 7, 47, 0);// Get date-only portion of date, without its time.

DateTime dateOnly = date1.

Date;A “date-only portion” that is a DateTime instance.

Right.

If you’ll inspect the docs, you’ll see that they’re actually setting the time to midnight (00:00:00).

That’s a bit different than “not returning” the time, isn’t it?Welcome to the foldYou may be wondering why I am going on a rant with this.

After all, it’s not that the language and API designers were trying to hide something or intentionally mislead developers — I’m sure they weren’t, and all details and quirks are extensively documented in every case.

Not to mention that people have been using these tools since a long time and in many cases to good results.

This concept of “dates” actually being Unix timestamps is software development’s status quo.

All engineers are aware of this and it’s rarely a surprise.

Still, you have to admit that giving something a mismatched name and then taking the effort of describing that it’s actually not what it appears to be is a little mind boggling.

Another question is — does this make anything easier?The answer is “of course not.

” Software development can be difficult as is, why then should we burden our thinking with additional, confusing layer of abstraction?If you were ever tasked with anything related to dates being transferred between boundaries of a single system (read: user submitting a form on a web page), chances are you came across timezone problems.

There are various ways that things can go wrong in this matter, to name a few:server using a timezone the developer is not expecting it to,some part of the communication flow deliberately or accidentally ignoring timezone information,serialization layer trying to be clever by adjusting the timezone and not taking into account that the operation can shift time,timestamps being used to convey data that doesn’t require as much precision,etc.

Either way, the outcome is the same — the time is off by a number of hours, sometimes changing the day as well.

The latter is very common in situations where timestamp is employed to represent a calendar date and the time portion is “removed” by setting it to midnight (i.

e.

what we’ve seen in the .

NET sample).

Now imagine that in order to get all the edge cases right, you should be taking daylight saving into account as well.

Headache and late hour bug reports guaranteed.

The hero we needIt would’ve been quite surprising if developers just kept putting up with this kind of nonsense through all these years without trying to do anything about it.

However, there is a limit to what you can accomplish with a tool that’s inherently broken.

Solving deep problem domains requires precise, robust solutions and this sometimes means binning what you already have and starting anew.

Java’s Joda Time library kicked off in 2002 and paved a new way in the field of dates and times handling.

They let go of the core Date class, instead providing a fresh set of building blocks, each crisply defined and tailored to tackle different time-related aspects.

To name a few of them, there is an Instant which functionally corresponds to the faulty antihero of this article, but is named correctly.

There is LocalDate which is just a date on the calendar, no strings (or milliseconds/timezones) attached.

There is LocalTime which is a time of day one could see when looking at their watch, regardless of what date it is.

There are Durations for telling how many milliseconds, or Periods for telling how many years/weeks/days have passed between arbitrary events.

Lower level concepts like Chronology ease working with different calendar systems.

You call daysBetween to tell how many days passed between dates and isBefore/isAfter to verify the order of events — no more folly with extracting millisecond counts and comparing numbers.

You could say the Joda Project were a hipster of their time, because they created a domain-driven API before Eric Evans’ book Domain-Driven Design made the concept popular.

Domain-Driven Design, among other things, puts emphasis on using precise, domain-specific language (ubiquitous language, as it’s called in the book) to directly model different concepts of given problem, including any interactions between them, in code.

Instead of using vaguely defined, catch-all solutions, engineers are required to get a deep understanding of issue at hand and model it in a way that straightforwardly corresponds to reality.

This translates to code that is easier to read and maintain, effectively resulting in fewer bugs.

Consider the following piece of code, possibly taken from a definition of some User class:private Date dateOfBirth;Looks completely legit, doesn’t it?.Now let’s pull the mask off this Scooby-Doo villain to see who they really are:private Instant dateOfBirth;Something like this would instantly (pun not intended) spark a discussion during code review.

Do we really need millisecond precision for a date of birth?.How will this be modelled in the database?.Will this be convenient to work with in other modules?And most importantly — why can’t we use a type that actually represents dates?.We can and we should:private LocalDate dateOfBirth;But Date is a core API, everyone is using it!If you have any recent Java/JVM development experience, you probably could’ve skipped most of previous paragraph as it was nothing new or surprising to you.

The truth is, Joda Time library had such widespread success across the community that, starting with Java 8, it got incorporated into JVM core API as java.

time package (with some modifications).

I’m not able to comprehensively advocate for .

NET, but they do have a port of Joda Time called Noda Time which as of time of writing is on the list of top 100 most popular NuGet packages.

JavaScript/Node.

js have one as well with js-joda NPM package.

However, its popularity of around 12K weekly downloads turns out pale in comparison with well over 8M of moment, which is arguably the most popular date/time library in JavaScript world.

The API moment provides is excellent, but at the end of the day it’s still just a wrapper around Unix timestamps and comes together with all the baggage I’ve described above.

The fact that a solution a mature platform like JVM has incorporated into its core is marginal within Node.

js spectrum means Node.

js still has some way to go, but let’s not forget it’s in our hands to take the effort and make a change for the better.

Final wordI’ve picked dates and times to make my point tonight, but I hope it’s clear that the whole idea is not limited to temporal matters only.

Domain-Driven Design approach suggested by the Joda Project shows how carefully chosen names can make a massive difference, facilitating development and maintenance of applications.

We should seek out frameworks and libraries which enable that, but more importantly, aim to tackle problem domains of our own projects with no less attention to detail.

Being explicit and deliberate about the way we describe solutions in code means that we have thorough understanding of the problem itself, and that leaves little room for costly logical mistakes.

.

. More details

Leave a Reply