Tuesday, 16 July, 2019 UTC


Summary

DateTime seems like a simple problem until you realize that you are storing a value that changes its display formatting depending on who is looking at it and where. We go over some JavaScript library options that can help, and discuss when it makes sense to use them.
DateTimes are interesting in any language. Most variables that contain a value remain the same whether you look at them on the server or in the web browser, but DateTimes are relative to where you are in the world. Not only does the display value change depending on your location, but how it’s shown to the user varies as well. While JavaScript provides some good methods to handle DateTime, sometimes you find yourself doing some complicated checks, like which event happened first or displaying relative time compared to local time. Once you start working with these scenarios, you start looking for solutions.
We are going to go over when you should use native methods and when you should start pulling in libraries to handle some of the more complex scenarios.
Native Methods
As you start using DateTimes, you’ll notice that JavaScript has the basic functions necessary for some simple operations which are all accessed via new Date(). The most basic use case for DateTimes is storing the current Date and Time with action and displaying it back to the user, like a blog’s publish date. You can accomplish this with native methods without having to pull in additional libraries.
There are a few lacking features when it comes to displaying relative times or custom formatting per locales. Also, time zones are only supported if you have a modern browser that supports Intl API. Once you start encountering these issues, there are two options: build it or seek a library that handles it for you. Since DateTimes are tricky, you definitely want to start looking around for some libraries that fill the gap for you.
When it comes to picking libraries, there are a few choices out there at the moment: Momentjs, Luxon, and date-fns. We are going to break down each library with what they handle and don’t handle.
Moment + Moment.tz
Moment.js handles every possible use case that you have for dates and times, and when paired with Moment.timezone it can handle time zones. The library has been for around seven years, so if there is a time-related problem, they have solved it or someone who has solved it has posted it to the internet.
When paired with Moment.timezone, it includes its own version of IANA Time Zone database, which means that, no matter the browser version, the combo can handle time zone, time calculation, and conversion, even in the oldest of browsers. This combination of libraries makes Moment.js + Moment.timezone a great choice for web apps that need to support older IE browsers.
Moment.js has been around long enough to collect its share of downsides as well. One of the biggest sources of bugs from Moment.js is that Moment objects are mutable. See the example below for details. This can an easy source for bugs.

Moment Mutable Quirk

//Common Bug var currentTime = moment(); var futureTime = currentTime.add(1, ‘hours’); //currentTime and futureTime contain the same information //Solution var currentTime = moment(); var futureTime = moment(currentTime).add(1, ‘hours’); //create a new moment object, then modifies it //currentTime and futureTime contain the different information 
Another thing to watch out for is the size of Moment.js when bundling or hosting. By default, it will include all locales with Moment.js, which can increase the bundle size if you are using webpack, and including moment.timezone will make it even bigger.
Despite these setbacks, Moment.js is a well-built, complete library that can solve any DateTime-related problem that you are encountering. If you think that you will have to support older browsers, you should definitely use Moment.js and only add Moment.timezone when you start doing time zone conversions on the browser side.
Luxon
Luxon has an interesting origin story along with a pretty intuitive API. Luxon began when one of the contributors to Moment.js began to play around with ideas and concepts that could not be easily implemented within Moment.js’s library. Luxon quickly grew into a library on par with Moment.js, with no one quite knowing where the future of either library is going. In fact, Luxon lives with the Moment.js repo, so there is no real competition, but just a different way of solving a similar problem. Along with solving a similar problem, Luxon solves some of Moment’s downsides while solving DateTime problems in their own way and style.
One of Luxon’s greatest strengths is Immutable objects, as you can see below. This can lead to more predictable behavior, which is great when it comes to displaying DateTimes across different time zones.

Luxon Immutable Objects

var currentTime = luxon.DateTime.local(); var futureTime = currentTime.plus({hours: 1}); //currentTime and futureTime contain different values 
Luxon has some of the best time zone support for all time libraries because of the Intl API that comes with modern browsers.
Using the Intl API reduces the bundle size of Luxon, since you are not bringing your own IANA time zone database along with each download. With their eye on bundling size, they have designed their library where tree-shaking will allow you to only bundle the locales that you are using along with English locale by default.
The unfortunate downside of leaning on the Intl API is that Luxon does not have time zone support if you are working in an older browser, and its implementation in some areas will vary based on the implementation of the Intl API in that particular browser. They do have a matrix of what is supported, which is helpful. For most web apps that are targeting newer browsers and consumers, this probably won’t be a problem. If you are supporting enterprise customers with older browser requirements, you might run into a few issues.
Overall, Luxon is a great library that should be used if you are doing quite a bit of DateTime work with a focus on modern browsers. Along with time zone support, it includes bundle-able locales, so you only have to include what you need. I feel that their API is much more intuitive, plus the code is generally more readable.
Date-fns
Moment.js and Luxon work off central objects, which keeps everything in a nice OOP (Object Oriented Programming) API, but this can have downsides within JavaScript. date-fns takes a different approach to the DateTime library. date-fns is a library of functions that work off the native Date object in JavaScript.
var currentTime = new Date(); var futureTime = addHours(currentTime, 2); //currentTime and futureTime contain different values 
Since date-fns uses the native Date object, it allows the library to be a grouping of functions, which allows for some improvements around bundling size and performance versus the other libraries due to tree-shaking. Another interesting perk is that locales are bundled in the same way as Luxon, which allows you to only import the locales you need at the time, with English being loaded by default.
Date-fns is in active development with some interesting features coming with V2 like time zone support and Intervals (calculations involving a start and end DateTime). Their V2 is still in the alpha stage, which has gone through a few iterations, so their changes may become stable soon. Until then, their V1 is lacking time zone support. Also, date-fns has pretty good locale support with the list growing, but it is not complete.
As a whole, date-fns’s approach of a true collection of functions is appealing, especially if you are using webpack. The lack of time zone support in V1 is a pretty big drawback and it may even be worth jumping to their V2 if you start using the library. I can even see scenarios where it would be ideal to use date-fns’s V2 Interval helpers in combination with another library for some calendar calculations.
Conclusion
Overall, I think that you should stick with using native Date object and don’t worry about DateTime libraries until you start going beyond the simple use case of storing a DateTime with an action. Once you get past that point, you have several options, and the best choice depends on your web app along with some personal coding preferences. If you need to support older web browsers, then Moment.js would be the obvious choice. If your client base is going to be on more modern web browsers, it comes down to a personal choice between Luxon and date-fns. Happy coding!
 

This blog has been brought to you by Kendo UI
Want to learn more about creating great web apps? It all starts out with Kendo UI - the complete UI component library that allows you to quickly build high-quality, responsive apps. It includes everything you need, from grids and charts to dropdowns and gauges.