Farewell, Moment.js!
Tags: javascript, typescript, news
Published: 2020-09-17 15:02:51

On September 15, 2020 Moment.js maintainers’ team [stated](https://github.com/moment/momentjs.com/commits/master/docs/moment/-project-status/00-intro.md) 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](https://www.npmjs.com/package/moment), 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](https://momentjs.com/) 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](https://day.js.org/). 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](https://moment.github.io/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](https://date-fns.org/) 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](https://github.com/GinMitch/farewell-moment-js) 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.