Monday, December 6, 2021

Is Luxon the Heir to the Moment.js Throne?

Moment.js is still widely regarded as the king of the JavaScript date libraries, despite being designated a legacy project by its maintainers in 2020. Now, the search is on for a worthy successor. Though it might be a little early to declare a winner, by all accounts, it is looking like Luxon is the front-runner. Not only is it the top-recommended alternative by Moment.js maintainers, but Luxon’s capabilities are somewhat more efficient on modern browsers. This tutorial will provide a comparison of the two libraries and show how to obtain the same results as Moment using Luxon.

Tree-shaking and Package Bloat

Although Moment.js is packed with tons of great features and utilities, if you are working on a performance-sensitive web application, it can cause a significant performance overhead because of its complex APIs and large bundle size: 235K (66K gzipped) vs. 66K (20 gzipped) for Luxon.

A few other Moment.js short-comings:

  1. Moment.js doesn’t support tree-shaking. Tree shaking is a term commonly used within a JavaScript context to describe the removal of dead code. In modern JavaScript applications, we use module bundlers (e.g., webpack or Rollup) to automatically remove dead code when bundling multiple JavaScript files into single files. This contributes to Moment.js’s huge bundle size and potential performance issues.
  2. Moment.js is mutable, and it causes bugs related to accidental and/or unintentional modification of object variables.
  3. Moment.js is based on Object-Oriented Programming APIs, so that methods may accept various parameter combinations, such as myDate.subtract(‘ms’, 50); and myDate.subtract(50, ‘ms’);. This also contributes to the first two issues.

Meanwhile, Luxon manages to provide an equally rich set of functionality despite also not supporting tree-shaking. In fact, it maintains a smaller minified size than some other popular date libraries that do support tree-shaking, such as date-fns. Its minified size is currently just under 90 KB, some 24 KB larger than Luxon.

One of my reasons for moving to Luxon is that its documentation includes a section specifically for Moment users who need to convert their existing Moment.js code to Luxon.

Immutability

So why are mutable Datetime objects a problem? Let’s look at an example that illustrates the danger:

var m1 = moment();
var m2 = m1.add(1, 'hours');
m1.valueOf() === m2.valueOf(); //=> true

This happens because m1 and m2 are really the same object; the add() mutated the object to be an hour later. Observe the equivalent code in Luxon:

var d1 = DateTime.now();
var d2 = d1.plus({ hours: 1 });
d1.valueOf() === d2.valueOf(); //=> false

In this case, the plus() method returns a new instance, leaving d1 unmodified. Object immutability means that Luxon doesn’t require copy constructors or clone methods.

Code Samples

Luxon has all of the bells and whistles that you’d want from a date library. Overall, Luxon is a tad more verbose than Moment, but part of that is that Luxon has a lot of static methods. For example, when we create a new date using Moment, we can call one of its many constructors:

var now = moment();
var fromTimestamp = moment((new Date()).valueOf();
var fromJsDate = moment(new Date());

Luxor’s global object is called DateTime. It doesn’t have a constructor; instead, it exposes several static methods:

var now = DateTime.now();
var fromTimestamp = DateTime.fromMillis((new Date()).valueOf());
var fromJsDate = DateTime.fromJSDate(new Date());

Another difference between Moment and Luxon is that the latter does not provide getters. Instead, it simply exposes the properties directly. Here are some of Moment’s getters in action:

var now = moment();
var year = now.year();
var month = now.month();
var day = now.date();

And here are Luxon’s properties for the same units:

var now = DateTime.now();
var year = now.year;
var month = now.month;
var day = now.date;

Comparisons and Transformations

Of course, the real reason for using a date library is to compare dates and times as well as modify them. Neither Moment.js or Luxon are lacking in those departments! Here’s some Moment code:

var now = moment();
var tomorrow = now.add(1, 'day');
var yesterday = now.subtract(1, 'day');
var lastDayOfMonth = now.endOf('month');

And here are the same operations using Luxon:

var now = DateTime.now();
var tomorrow = now.plus({ days: 1 });
var yesterday = now.minus({ days: 1 });
var lastDayOfMonth = now.endOf('month'); //same as Moment!

Moment Dates may be compared using one of the library’s many comparison methods such as the following:

var now = moment();
var tomorrow = now.add(1, 'day');
var isBefore = now.isBefore(tomorrow); //true
var isSameOrBefore = now.isSameOrBefore(tomorrow); //also true

In this respect, Luxon differs significantly from Moment, in that Luxon Dates may be compared using the standard comparison operators, such as <, <=, > and >=:

var now = DateTime.now();
var tomorrow = now.plus({ days: 1 });
var isBefore = now < tomorrow; //true
var isSameOrBefore = now <= tomorrow; //also true

Formatting

Both libraries format dates as ISO 8601 strings, but with some differences. Moment provides a format() method that may be invoked without parameters:

moment().format(); // 2021-05-09T16:38:52-04:00

Luxon overrides the default toString() method to generate an ISO 8601 string. Oddly, it includes milliseconds, whereas Moment’s format() does not. To produce the exact same format as Moment, we can provide a format string to the toFormat() method as follows:

DateTime.now().toUTC().toFormat("yyyy-MM-dd\'T\'TT"); // 2021-05-09T16:38:52-04:00

Conclusion

If you’re looking to move from Moment.js to a different JS date library, I strongly recommend Luxon. Not only is is an excellent replacement, but it just may be the easiest to switch to, thanks to Luxon’s thorough library comparison and guide.

In an up-coming article, we’ll get better acquainted with Luxon by creating a small web utility to show a date in different time zones.

 


Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Popular Articles

Featured