On September 15, 2020 Moment.js maintainers’ team stated that one of the world’s most popular JavaScript date library has come to an end.
It doesn’t need any introduction: according to NPM, as of September 2020, it has over 14 million downloads weekly and more than 46000 dependent open source packages. Moment.js has been around since 2011, but its developers have their own reasons to shut down its active support, which also includes immutability and support for “tree shaking”.
There’s no need to whine about it but a good reason to take a look at its successors. Obviously, I must tell you that you don’t have to immediately scoop through all of your projects and replace Moment.js; if there are not many places where you use it, go ahead and upgrade but since now anything you start working on should probably not use it anymore.
Here is an overview comparison of several date libraries which are recommended as a feasible replacement. We’ll stick to TypeScript as an increasingly popular language used by a lot of projects (I mean, there are really a lot).
To begin with, let’s create a pretty basic React app, so we can jump start this journey and see the results immediately:
yarn create react-app play-date --template typescript
Moment.js
Let’s take a look at Moment.js and see how simple it is to start using it (or should I now say “was”?).
First thing we need before using Moment.js in any project is to install it:
npm i moment
or yarn add moment
Then import it in a component and you're good to go:
import moment from 'moment';
Date as object
const test1 = new Date('2018-01-16'); // Date
First, we need to convert it:
const obj1 = moment(test1); // Moment
That's it — nice and simple! Moment.js takes a Date object “as is” and turns it into its own object, so we could operate on it.
And if we need to know what year is inside, then we could easily get it:
obj1.year(); // number
Or count how many days have passed since then:
moment().diff(obj1, 'days'); // number
Date as string
const test2 = '2016-07-20'; // string
Convert it:
moment(test2); // Moment
Moment.js also takes a string “as is” so you should only care about its format.
Though Moment doesn't restrict you with some special format, it may not recognize some real junk.
Day.js
Then we move on to the Moment’s nearest successor — Day.js. If you ever used Moment.js, it should be really easy to replace it with Day.js, it’s not exactly the same but still worth a try.
Start using Day.js by adding it to your project:
npm i dayjs
or yarn add dayjs
Then import it:
import dayjs from 'dayjs';
Even to those of you who have never heard of Moment before the two previous lines should ring a bell as if you’ve seen this before. And you’d be right to say that it looks exactly like Moment’s installation and import.
Date as object
const test1 = new Date('2018-01-16'); // Date
Day.js might not be a drop-in replacement for Moment.js but it gives you pretty similar API and uses the same concept of turning everything into its own object.
Convert it:
const obj1 = dayjs(test1); // Dayjs
And if we need to know what year is inside, then we just get it:
obj1.year(); // number
Or simply count how many days have passed since then:
dayjs().diff(obj1, 'day'); // number
The thing about using Moment.js is that you could count days or years as well as day or year — that doesn’t matter at all. We couldn’t say the same about Day.js, but on the other hand that's the price you pay for having a really lightweight library.
Date as string
const test2 = '2016-07-20'; // string
And again we need to convert it. Day.js as well as Moment.js will parse any string given its ISO 8601. But if you want to parse anything different from that, you must provide it with the desired format:
dayjs(test2, 'YYYY-MM-DD'); // Dayjs
Luxon
Our next contestant gives us a subtle hint that its core maintainers is nearly the same as Moment’s.
Take the usual step and add Luxon to your project:
npm i luxon
or yarn add luxon
Back off a little bit. Remember we decided to go on with TypeScript? Well, Luxon in contrast to the other libraries doesn’t ship with its own type definitions, so your modern IDE should scream about when you try to import it. Here’s the way to add TypeScript support:
npm i @types/luxon
or yarn add @types/luxon
Then you may proceed to another usual step:
import { DateTime } from 'luxon';
Date as object
const test1 = new Date('2018-01-16'); // Date
If you think we should wrap (or convert) the date to use it then you’re right:
const obj1 = DateTime.fromJSDate(test1); // DateTime
Rather than Moment.js, Luxon will not provide you with a single “entry point” to do it. Refer to its guide or use code completion to parse your date.
Get the year value back:
obj1.toFormat('yyyy'); // string
Here we get result as string because toFormat() could give us nearly anything with the token parameter.
Count how many days have passed since then:
DateTime.fromJSDate(new Date()).diff(obj1, 'days').as('days'); // number
The syntax is trying really hard to look similar to Moment.js, but it's a way longer than I personally like and it gives you an awfully precise result.
Date as string
const test2 = '2016-07-20'; // string
And again we need to convert it using the corresponding method. Though, we could've used fromFormat() if this string was not ISO 8601 but let's stick with fromISO() for now:
DateTime.fromISO(test2); // DateTime
date-fns
To move on to the next library, we need to add date-fns just as usual:
npm i date-fns
or yarn add date-fns
And here comes its first pitfall — you could not import it like Moment.js or Luxon, each of date-fns’ functions should be added to the import statement separately thus you can not use the benefits of code completion.
It requires you to know which function you need or refer to its guide to find the right one:
import { differenceInDays, getYear } from 'date-fns';
Date as object
const test1 = new Date('2018-01-16'); // Date
This library is based on so-called “helper functions” which rely on native Date object manipulations, which is really great. Therefore, we need no conversion to use it right away!
Let's get a year from it again:
getYear(test1); // number
And count how many days have passed since then:
differenceInDays(new Date(), test1); // number
Date as string
const test2 = '2016-07-20'; // string
Unfortunately, date-fns could not recognize the string format for us so to parse it we must explicitly provide the string format which is not the point if your project is well-documented and consistent:
parse(test2, 'yyyy-MM-dd', new Date()); // Date
All code samples here available on GitHub within the React app.
I must say that this quick overview of Moment’s possible replacements doesn’t make a claim to be a full guide to these libraries or a full list of “What should I use instead of Moment.js?”.
If you know better tools — please let everyone know by mentioning them in the comments.
Top comments (8)
For one of the most common use cases, formatting dates, no libraries are required at all (except maybe a polyfill, depending what locales and environments you need to support). You can just use the
Intl.DateTimeFormat
constructor.For example:
I have just switched from momentjs to dayjs, the size of momentjs was too huge compared to the minimal set of features we need from it. Sad to see it gone though. It had a good run.
I admire the devs behind this project and their persistence. 😉
Should be a challenging lib to make, due to all the math that goes into it 😉
import * as DateFns from 'date-fns'
should work.didn't I recently hear in some podcast the developers are working with the tc39 group to create a standard, that will be available in js?,... then we don't need another lib and we don't need to put it into out bundles.
I love date-fns!!!
I saw this! fns!
Nice to know there will be good alternatives.