DEV Community

Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

The 7 best JavaScript date libraries

Adding working dates to your application always seems like an easy task in theory, until you attempt to do it. There is always something getting in the way, whether it’s a time zone problem when trying to internationalize your website, issues showing the date in the needed format, or even trying to do some basic arithmetic with them (i.e subtracting three days from a date, it shouldn’t be that hard, should it?).

The problem is that, sadly, JavaScript is not really prepared to natively deal with dates. Which is a bit ironic considering it does have a Date object we can use for some basic operations.

What do I mean then, when I say JavaScript is not ready? I mean that the API for this object is not rich enough for our daily needs, it doesn’t have the high-level support you’d expect from such an object to take on problems such as internationalization, timezone support and so on.

Here is where the libraries I’m going to be reviewing come into play. These seven date libraries add layers of abstraction on top of JavaScript’s Date object and make it actually useful.

LogRocket Free Trial Banner

moment.js

Reviewed version: 2.24.0

Moment.js is one of the oldest and best known date-related libraries for both, Node.js and vanilla JavaScript (making it browser compatible). And because of this, they’ve had the time to make it compatible with many of the most common web-development utilities, such as:

It offers a great API without having to modify the Date object’s original prototype, instead, they created a wrapper object around it, making sure they don’t pollute the original namespace.

As a quick example, here is how you’d set up the current date. Add seven days, then subtract a month, and finally set the year and time values. All in a single line of easy-to-read code, like this:

moment().add(7, 'days').subtract(1, 'months').year(2009).hours(0).minutes(0).seconds(0);

They support over 20 different locales, so if you’re aiming at solving your internationalization problems, moment.js is a good bet.

Plugin ecosystem

A good measure of the success and overall utility of a particular library is by checking out the plugin/extension ecosystem that exists around it. In the case of moment.js, there are 22 officially supported ones. That might not be a big number at first glance, but if you consider that all these libraries were designed around a single object, the Date object, then having over 20 plugins is definitely a great sign.

You can find their entire list of plugins on their documentation page, but some of the most interesting out there are:

The twitter time

This one allows you to format your dates and times just like Twitter does (notice how they abbreviate their time ago-like dates with a single letter when it’s clear enough, such as 1h for “1 hour ago” or 2d for “2 days ago”).

twitter time

With this plugin you can simply do something like:

moment().subtract(6, 'days').twitterShort();

To return “6d”.

Parse format

How many times did you write the date format when trying to display your dates in one specific way? Something like YYYY-MM-dd or similar variations. But always manually, we write it, and then the library formats the date accordingly.

This plugin, instead of formatting the date, parses a date string and returns the actual format for you to re-use.

So you can do something like:

var format = moment.parseFormat('Thursday, February 6th, 2014 9:20pm');
// format will contain: dddd, MMMM Do, YYYY h:mma

This particular plugin is great for adding dynamic behavior to your formatting logic, for example, making the formatting dynamic and allowing your users to enter a date example, instead of having them learn how to configure their own format.

Timer

This one is actually a full re-write of JavaScript’s setTimeInterval and setTimeout functions, allowing you to mix moment’s syntax and create a much more powerful timer.

You can do something like this:

var timer = moment.duration(5, "seconds").timer({loop: true}, function() {
  // Callback
});

Which is already a lot easier to read and understand than:

setInterval(function() {
  //Callback
}, 5000)

Again, there are over 20 plugins, I invite you to check out their documentation page and review the list for yourself.

date-fns

Reviewed version: 2

Advertised as the lodash of date libraries, date-fns tries to provide a better experience than the one Moment.js is able to give.

It’s API is quite extensive with over 140 different time-related functions, their creators and contributors hope to make you switch from using Moment and get hooked into their own solution to time management.

Some of the key aspects of this library are:

  • All functions are grouped by file , allowing you to import just what you need without having to bloat your project for just 2 methods that you’re really using. This is especially useful for front-end developers who need to optimize their bytes-per-JS-line , since every bit counts. In the case of Node.js developers, this is still useful to keep imports and requires more organized (I’ll show you some examples in a bit).
  • Unlike other libraries (looking at you Moment.js), t he date objects returned by date-fns are immutable , helping you stay away from unwanted modifications and countless hours of debugging.
  • The FP sub-module provides a nice set of FP-related functions, helping you easily compose complex behavior with just a few lines of code.
  • They support a total of 57 different locales , so if you’re aiming for internationalization, here is another great option!
  • They have TypeScript and Flow support.
  • Last but not least, their documentation is very detailed which is something I always appreciate from a library, especially with the ones that have such an extensive API.

Some code samples

Let’s quickly run through some code samples to give you an idea of what makes this library unique.

const { addYears, formatWithOptions  } = require('date-fns/fp')
const { es } = require('date-fns/locale')

const addFiveYears = addYears(5)

const dateToString = formatWithOptions({ locale: es }, 'd MMMM yyyy')

const dates = [
  new Date(2017, 0, 1),
  new Date(2017, 1, 11),
  new Date(2017, 6, 2)
]

const toUpper = arg => String(arg).toUpperCase()

const formattedDates = dates.map(addFiveYears).map(dateToString).map(toUpper)
//=> ['1 ENERO 2022', '11 FEBRERO 2022', '2 JULIO 2022']

This example shows two of the points I made above: the functions-per-file mechanics, allowing you to only require the bits you actually need (both imports take advantage of that in the example) and the functional programming helper functions. Notice how with those two imported functions (addYears and formatWithOptions) we’re composing the entire process in the final line (those two and the toUpper anonymous function as well).

A quick note about the code: Even though it’s the same example as the one shown on the library’s homepage, I had to adapt it to be compatible with Node.js.

Luxon

Reviewed version: 1.16.1

Luxon is a very interesting project because if you look at it’s URL, it lives under the Moment.js project, so why is it there? You can read the whole story from the author himself, but the main gist of it is that it attempts to be a better version of Moment, however:

  1. It doesn’t really support all features Moment.js supports at the moment.
  2. It relies heavily on the Intl API from modern browsers, so older ones will have a hard time dealing with internationalization-related methods.

One of the main differences in Luxon when compared to it’s predecessor (if we can call Moment.js that), is that this time around, all objects are immutable (notice a pattern here? One could argue Moment.js made a poor decision making their objects mutable and everyone in the community went out of their way to fix that problem).

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

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

In the above example you can see this difference in action, while with Moment.js (first example), you’d run into that kind of “problem” (the quotes are there because the problem only happens if you’re not paying attention) since the add method would mutate m1 instead of returning the new value on m2, the API from Luxon would prevent you from having that problem since plus returns a new object on d2 instead of modifying d1.

The other big difference with Moment.js is the fact that internationalization is based on the Intl API from browsers. Essentially, what this means is:

  1. You don’t need extra configuration files to deal with locales, the browser does that for you.
  2. If you want to make this work on Node, you’ll need either a polyfill module or build node with full ICU support. If you don’t do either one of them, the library will still work, but localization functions will do nothing.

There are other changes that might be of interest to you if you’re a Moment.js user, so make sure to check them out on their documentation.

DayJS

Reviewed version: 1.8.14

DayJS attempts to be a minified version of Moment.js (are we seeing the patterns here, people?). There is something to be said for a library that claims to have the same API of Moment.js and reduce its file size by 97%. That’s right, where Moment.js full minified file weights a total of 67,9Kb, DayJS minified file is only 2Kb. That’s crazy and yet they have support for internationalization, plugins and everything else.

You can think of DayJS as lodash when everyone was using underscore (remember?). Suddenly lodash came into the picture boosting a similar claim, they had a very similar API with a reduced footprint, winning the hearts of many front-end developers who, as I mentioned above, are always trying to save as many bytes as possible to reduce loading times.

And just like Moment.js, this library has around 20 plugins officially supported which you can check out on their documentation.

Finally, while this library appears to be everything it claims to be and developers are starting to adopt it as seen in the following download trends chart:

day js downloads

MomentJS is still rocking the monthly downloads, since it’s been around for 8+ years (compared to the 1+ year of DayJS). It’ll take some time, but if MomentJS doesn’t adapt (maybe Luxon could be an option?) it’ll eventually be replaced by this new kid on the block.

There is no point in showing code samples since the API is practically the same as MomentJS, just check their official documentation if you need anything in particular and switch to DayJS if you’re worried about loading times and data usage (a big problem for mobile web developers).

ms

Reviewed version: 2.1.2

To change things up a bit, this next library was not created as a replacement for MomentJS (I know, shocking!) but instead, it only has one job, and it does so very well.

The objective of MS is to convert any kind of date format into milliseconds and back.

This is a very narrow use case, I know, but as you very well know, turning dates into milliseconds has its advantages, especially if you’re trying to do things like comparison, and some forms of arithmetic operations (it’s a lot easier to add 1000 milliseconds to a number, than saying you need to add 1 second to a Date object).

So in other words, with this library you can do things like this:

ms('2 days')  // 172800000
ms('1d')      // 86400000
ms('10h')     // 36000000
ms('2.5 hrs') // 9000000
ms('2h')      // 7200000
ms('1m')      // 60000
ms('5s')      // 5000

ms(60000)             // "1m"
ms(2 * 60000)         // "2m"
ms(-3 * 60000)        // "-3m"

Now, I know what you’re thinking, why? Who’s using it? Well, given the fact that this library has over 30 million downloads every week , I’d say it covers a very specific and yet, common use case. So consider checking it out if this is all you need for your time-related logic.

js-joda

Reviewed version: 1.11.0

Yet another general time management library aiming at replacing MomentJS and others from the above list. It tries to differ from others like MomentJS by avoiding the same wrapper around the Date object technique and instead, it implements the entire logic from scratch.

Is that better? The jury is still out on that one, it probably gives the maintainers more room to play around with basic concepts and twist them in ways the Date object can’t go. That being said, this library is marginally smaller than MomentJS (sitting at around 40Kb) far away from the tiny 2Kb of DayJS.

It does, however, provide immutability (shocking) and domain-specific classes, helping you, the developer, write cleaner OOP code.

A very interesting feature of js-joda is the extensibility it provides. As immutable objects don’t really have setters, this library provides the with method, which returns a new object with the new value set. And if instead of setting it a value, you set it a special object, you can extend the way you get values.

Let me show you:

// implement a TemporalAdjuster that returns the next or same even day of month
var nextOrSameEvenDay = {
  adjustInto: function(t) {
    return t.dayOfMonth() % 2 === 0 ? t : t.plusDays(1);
  }
};

LocalDateTime.parse("2012-12-23T12:00").with(nextOrSameEvenDay); // '2012-12-24T12:00'
LocalDate.parse("2012-12-24").with(nextOrSameEvenDay); // '2012-12-24'

Basically, we’re parsing a date string (nothing fancy there), and then with the custom object (notice the special adjustInto method) we’re adding a very random behavior, but valid none the less.

I would personally recommend this library if you’re looking for this type of flexibility, otherwise, I’ve already covered better ones above.

Spacetime

Reviewed version: 5.9.0

I couldn’t leave out a time library called Spacetime, sorry, but my nerdy side won that battle. That being said, this one has a very interesting focused: timezones.

Yes, it provides a MomentJS-like API, with immutable objects (yawn!) too, but the main focus of this library is to help you deal with timezones easily. And remember, timezones tend to be one of the main issues when dealing with any type of internationalization development, so already this looks promising.

Let me show you some code:

const spacetime = require('spacetime')

let d = spacetime('March 1 2012', 'America/New_York')
//set the time
d = d.time('4:20pm')
console.log(d.time())

d = d.goto('America/Los_Angeles')
console.log(d.time())
//'1:20pm'

That was super easy, wasn’t it? A note about Spacetime though, is that it doesn’t rely on the Intl API like Luxon did, so the library itself is not really lightweight sitting at around 40Kb. That being said, timezones still follow the IANA naming convention, which is great for standardizing your code.

Another cool thing about our last library is that it can observe daylight saving times where applicable, so the following happens:

d = d.goto('Eastern Time') // "America/New_York"
d = d.goto('PST') // automatically becomes 'PDT' in the summer

There are other nifty methods such as season which returns the current season for a particular date (either summer/winter/spring/fall is returned) as well as hasDST and inDST which return whether a timezone ever uses daylight saving times and if it has it active at the particular date/time configuration.

Finally, extending Spacetime is quite straightforward, which helps add extra features, such as:

spacetime.extend({
  isHappyHour: function() {
    return this.hour() === 16
  }
})
d = d.time('4:15pm')
console.log(d.isHappyHour())
//true

Conclusion

These were 7 of the most common JavaScript libraries that deal with date and time. Given the existing information and the usage data available online, if you’re having to deal with very complex date-time related features my recommendations would be going with either MomentJS because it’s a classic and time tested library, or simply try the brand new and faster model: DayJS , same API, better object management and all-around smaller footprint.

If on the other hand, you have very specific needs, think about going with ms or Spacetime.

Which libraries are you using now? Did I miss yours? Leave a comment below and let us know!

See you on the next one!


Plug: LogRocket, a DVR for web apps

 
LogRocket Dashboard Free Trial Banner
 
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
Try it for free.


The post The 7 best JavaScript date libraries appeared first on LogRocket Blog.

Top comments (3)

Collapse
 
declan_byrd profile image
Declan Byrd

What is the use case for not using the native Date functionality in js? Surely using the Date methods would be a preferred option given that it reduces the number of packages you use?

Collapse
 
deleteman123 profile image
Fernando Doglio

The Date object's API is not rich enough, I like to think of it as the assembler to these libraries C.
In other words, most of them use it at their core, but they add several layers of abstraction in order to help make your code more readable and easier to maintain.

Look at the example from the MomentJS section:

moment().add(7, 'days').subtract(1, 'months').year(2009).hours(0).minutes(0).seconds(0);

You can't do that with the Date object using that syntax, in fact, there are no methods to add or substract anything to its original value. The fact that there are so many libraries out there I think is literally proof that Date is not getting the job done.

Collapse
 
declan_byrd profile image
Declan Byrd

So guessing from the example that it primarily helps with the readability of complex date calculations rather than the readability of a date string. I haven't had to use a package for dates in any of the projects I've worked on so genuinely interested what the decision rational is and what Date doesn't do that forces developers to create packages for that functionality.