loading...

Farewell, Moment.js!

mullinsmikey profile image Michael M. ・5 min read

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 comments.

Posted on by:

Discussion

pic
Editor guide
 

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:

const dateFormat = (lang, country) => {
    const formatter = new Intl.DateTimeFormat(
        `${lang}-${country}`,
        { dateStyle: 'full' },
    )

    return date => formatter.format(new Date(date))
}

dateFormat('en', 'AU')(Date.now())
// Friday, 18 September 2020

dateFormat('th', 'TH')(Date.now())
// วันศุกร์ที่ 18 กันยายน พ.ศ. 2563
 

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 😉

 

LOL, did they finally run out of ideas on how to transform dates.. I love this library, but im sure people will be maintaining it. I mean really how many ways do we need to parse and format UTC lol. Honestly its slow AF so i end up doing bitwise anyways. Thank you for sharing :)

 

You could not import it like Moment.js or Luxon

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.