Date. Let's discuss them.
This is the second installment in a series of posts about handling date and time in web applications:
- Beyond DateTime: a domain-driven approach to date and time
- Storing dates and times in databases: the painless way
- Your application needs a clock
Date is perhaps even a larger mess than PHP's
I could stop the argument there at the point I made in the previous post:
Date is a single class used to represent many different temporal concepts, and as such it can hardly represent either of them properly. And it adds a bunch of other issues on top of that, including:
date.setHours(date.getHours() + 2), which even returns a number (of milliseconds since the epoch) instead of an instance of
setHours()correctly, it modifies the original instance in-place. This can easily shoot you in the foot. Temporal data are value objects, and value objects should be immutable.
setUTCHours()). This is a very limiting factor if you're writing an application that users access from different time zones.
There are some popular wrappers over
Date available, perhaps the most notable one being Moment. Although it provides a significantly more pleasant API and even has a timezone-aware plugin, it suffers from the same other issues too: it is mutable, and it only provides a single class to represent various temporal concepts.
Then there's Luxon, a de facto successor to Moment. It finally brings immutability into the game, yay. It also 'abuses the Intl API horribly to provide time zone support,' which comes at the cost of some parts of the Intl API (and thus also Luxon) being browser-dependent. Moreover, the main class in Luxon has a more fitting name of
But the name doesn't change the fact that it is still a single class. If you kindly let me borrow the toolbox metaphor from my previous post: you need a wide selection of screwdriver bits but all you get from any
Date-based solution is a hammer.
We have to step away from
My package of choice for working with date and time is
js-joda. It too draws a lot of inspiration from Java's Date and Time API and its preceding efforts, and provides all the familiar concepts and classes including
ZonedDateTimes with distinct
Periods, all immutable and each with a fine-tuned set of methods that prevent you from shooting yourself in the foot.
First, to my disappointment, the package is not widely adopted. Pretty much any date-time widget or component, ranging from date pickers, to calendars, to time-ago formatting helpers, etc., works with
Date or Moment. If you choose to use
js-joda, you have to do conversions on all these edge spots. Luckily, the package provides simple conversion functions, but you still need to be careful with it.
Second, if you want to work with time zones client-side, it's heavy. The Intl API still doesn't provide much information about time zones (unless you 'abuse it horribly' like Luxon does), so for
js-joda to be able to support other time zones than the user's local time, it needs to bring along a substantial portion of timezonedb (in fact, funnily enough, extracted from Moment's timezone plugin). You should limit the number of places where you need to work with multiple time zones, and make use of techniques like code splitting to lighten the resulting bundle.
Third, basically the same applies to localization. For the lack of support in the Intl API,
js-joda ships with its own localization packages, prebuilt for the most common locales, and available with a more complex setup for any locale included in
cldr-data. Again, you can take measures to minimize the resulting bundle size, or convert
js-joda objects to native
Date and use the
Intl.DateTimeFormat API directly.
Apart from those three issues,
js-joda is an amazing tool with great value.
Another huge part of working with date and time client-side is the information exchange with the server. You need appropriate formats to be able to send temporal values to the server and receive them back. This is not always straightforward with
Date-based libraries, for that matter), for all the reasons I've listed above: it only supports local time and UTC, and it's a single class used to represent multiple concepts, naturally forcing you to use a single format to represent values of different kinds and purposes.
js-joda makes this effortless. Assuming that you're already using
brick/date-time server-side, any temporal data you need to send from the client can be mapped onto a matching PHP class, and vice versa. Since both packages offer very good support for ISO 8601, a widely adopted international standard that prescribes information interchange formats for time-related data, there is nothing left for you to worry about.
Date, and thus, a proposal of a more robust Temporal API has made it all the way to TC39 and is currently at Stage 3, which means it could be included in the ECMAScript specification within a couple of years. We'll probably need to include a polyfill for Safari for another few years, but I'm looking forward to it regardless.
js-joda is as good as it gets!