You might not need date-fns
Tags: javascript, date, time, datefns
Published: 2020-09-29 22:14:58


Hola! Lazy dev here and today we are going to discuss [date-fns](https://date-fns.org/). People often choose date libraries before they really need it. "How we will format the date?", "Are there any alternatives?" 

But really, are there? 

## Am I a hater? 

Sorry, this question was required. No, I'm not. Moreover, I was a super-active user and evangelist of date-fns. I am the creator of [date-io](https://github.com/dmtrKovalenko/date-io) and [@material-ui/pickers](https://next.material-ui-pickers.dev) which have been proposing to choose date-fns over the other date libraries. 

{% details But one day I said that date-fns is not a panacea %} 
 After the twitter [thread](https://twitter.com/dmtrKovalenko/status/1254414963306909699), that was transformed in this blog post, date-fns' maintainer [blocked me](https://twitter.com/dmtrKovalenko/status/1309854060284186630) everywhere because it says that you might not need it. So probably this thread contains some useful information for people that choosing date lib – so I decided to share it in the blog as well! Hope you will have some fun reading it :)  {% enddetails %}


That's it for prerequisites so let's start the discussion 

## You might not need a date library at all

First of all, when you need to only show date values in the user-readable format – **you can avoid date libraries at all**. Today all the modern browsers (even IE11) and node.js [perfectly support](https://caniuse.com/?search=datetimeformat) `Intl.DateTimeFormat`! 

![can I use Intl.DateTimeFormat](https://dev-to-uploads.s3.amazonaws.com/i/u1091yrhgti9gxwdi3cr.png)

This means that if your task is only to show the date/time value in a user-readable format you can do the following:


```js
const date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
// Ouput will depend on user locale and timezone 
console.log(new Intl.DateTimeFormat().format(date));
```

It perfectly supports **native IANA** timezone and locale formatting. It means that you can not include locales in the bundle at all. 

```js
const date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
// Results below assume UTC timezone - your results may vary

console.log(new Intl.DateTimeFormat('en-US').format(date));
// expected output: "12/20/2012"

console.log(new Intl.DateTimeFormat('fr').format(date));
// expected output: "20/12/2012"
```

## If you need more

But there is a problem. When you need more than formatting – for example, parsing or you are working with dates too often so the native (not really best) `Date` API is not enough. You probably will start looking for some helpful date-management library. 

> 🌈 One wonderful day we will probably be able to get rid of all libraries in favor of native API. [Here](https://github.com/tc39/proposal-temporal) is the proposal for `Temporal`, which provides a nice functional API for working with `Date`.

But today you probably will pick up date-fns. Nothing personal – only statistics. Date-fns is the most popular date library as of now. What about moment.js? It is [dead](https://momentjs.com/docs/#/-project-status/).

Today date-fns is much more often used for new projects. Here are [downloads stats](https://github.com/dmtrKovalenko/date-io#projects) from date-io.

![date-io stats](https://dev-to-uploads.s3.amazonaws.com/i/43uuzg4ja7hg9cc46nro.png)

Statistically, you will pick date-fns. But do you **really need** it? 

Let's discuss some criterias that are commonly used to choose the date library, and see does date-fns is the best one or not? 

## Bundlesize 

Date-fns is solving **only 1 problem much better** than any other date library. And that's not a bundlesize. 🎉 Surprise 🎉 date-fns takes mostly 18kb gzip without locales. [Dayjs](https://github.com/iamkun/dayjs) takes 6 (yes six kb). 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3190xkekugphaemwa5cg.png)

{% details But if compare not gzipped, but parsed size – date-fns is the biggest one %}

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/umxoo13hmoshhnd7tiu1.png) 
{% enddetails %}

Ok. Ok. The problem date-fns solving REALLY nice is tree-shaking. Because each function has its own entry point and exported as esm, unused code will be removed from the bundle, right? 

### Treeshaking

Let's create a more "real-world" example, that uses the hardest to implement manually functions: 

- Formatting
- Parsing
- Display time from X to Y
- 3 locales

#### Result:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n7tea59gefbgi5i4b35y.png)

As you can see date-fns takes 13.88kb gzip when only importing the most important functionality. It is a lot.

Here is a pretty fun example of a react datepicker that has a peer dependency on date-fns. Date-fns takes 3 times more space than the datepicker itself and mostly 1/3 size of react. And it's only to make a single date-picker work. 

![react-nice dates](https://dev-to-uploads.s3.amazonaws.com/i/37ztkhqal0pd1ubkohp2.png)

Also as you saw in the [bundlesize stats](#result) luxon did not change its size at all. This because luxon npm package provides only commonjs output which is not tree shakeable. So maybe one day it will become smaller. 

But do not forget the most wonderful thing about Luxon – it is built over native `Intl` – so it doesn't bundle locales at all. You can support even 50 locales without any additional bundlesize for date formatting!

{% details P.S. All date-fns' 75 locales bundle takes 80kb gzip %}
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6r0lofncipyjgqtwtx16.png)
{% enddetails %}

### Bundlesize conclusion 

Date-fns is **not lightweight** library for date/time management. There are underrated alternatives – e.g. [Dayjs](https://github.com/iamkun/dayjs) is much smaller when using around the same functionality. 

## API 

The next criteria for choosing a library would be the API. API must be clear, well-typed, and comprehensive. And here the most unclear for me personally – why everybody is choosing date-fns? 

Date-fns design is pretty straightforward – you have a separate function for everything. And this is totally perfect, but unfortunately, not for all javascript developers. The problem is that javascript doesn't have native function composition utils. 

I mean that some complex code with date-fns is completely unreadable: 

```ts
function checkIsBeforeDateFns(time: Date, maxTime: Date) {
  return isBefore(
    setMilliseconds(setSeconds(setMinutes(time, 0), 0), 0),
    maxTime
  );
}
``` 

Function executions need to be read like from the inside out. The first function call will be `setMinutes` and the last will be `isBefore`. 

Let's compare the same functions in dayjs and luxon. They are using the old good chaining API. Most `developers`/`editors`/`linters`/`static analyzers` work like a charm with such APIs. 

```ts
function checkIsBeforeDayjs(time: Dayjs, maxTime: Dayjs) {
  return time.minute(0).second(0).millisecond(0).isBefore(maxTime);
}

function checkIsBeforeLuxon(time: DateTime, maxTime: DateTime) {
  return time.set({ second: 0, minute: 0, millisecond: 0 }) < maxTime;
}
```

Much readable right? This is actually overall a common problem in functional programming. And it can be easily fixed by using some of the function composition techniques. For example here are the same functions with [date-fns/fp](https://date-fns.org/v2.16.1/docs/FP-Guide) submodule and [ReasonML](https://reasonml.github.io/) (now Rescript) – native functional language compiling to javascript. And this is awesome 💜

```ocaml
let checkIsBeforeDateFns = (time, maxTime) =>
  time
  |> DateFns.setMilliseconds(0)
  |> DateFns.setSeconds(0.)
  |> DateFns.setMinutes(0.)
  |> DateFns.isBefore(maxTime);
```

This is still just 4 function calls. But much much more readable. Beautiful! 

> By the way I am the maintainer of date-fns [binding for ReasonML](https://github.com/dmtrKovalenko/reason-date-fns). Bring us a ⭐️

But ask yourself – **do you and _more important_ your team** are ready for functional programming? And do you have all the required tools for it like [`pipe` or `compose`](https://www.freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/)?

If yes – take date-fns and be happy with functional programming 👨‍💻👩‍💻.

## Performance 

You should not think about performance before the problem was encouraged. 

> Premature optimization is the root of all evil © Donald Knuth

The performance difference will be visible only on the thousand function calls per second. But if you still interesting in performance differences between date-fns and the other libraries: 

Short results from our [date-io benchmark](https://github.com/dmtrKovalenko/date-io/tree/master/packages/benchmark): 

- Date-fns is the fastest for date calculations (add, subtract, before, etc)
- Date-fns is the fastest for date parsing
- Moment is fastest for formatting (ha-ha didn't expect moment here) 

Yes, date-fns is really fast because it works directly with a native date without creating any additional wrapper. Dayjs focused on size instead of speed and Luxon is using `Intl` which is super slow 🐌. 

So yes date-fns is the best option if you have performance issues with other libs. But do you really have? 

## Conclusion

Make sure that the author of this post is incompetent, subjective, stupid, awful, and lazy. So you must reach your own conclusions for your particular project and team based on many factors. 

BTW [here is the repo](https://github.com/dmtrKovalenko/date-fns-comparison) with all date-fns comparison stuff from this post, you can check it out, play with bundlesize and API.

I will really be happy if you will think about date/time libraries in javascript and the requirement of date-fns after this reading 🤓

In the author's humble opinion there are no reasons to choose date-fns if you are not cooking functional programming. And, unfortunately, as far I can see literally nobody using their really good functional approach 😿. 

So, in conclusion: if this lazy author one day will start a new project in javascript and will need some kind of date/time manipulations he will probably do the following:

- Try to start with native Intl formatting
- When lib will become really needed choose dayjs – because its 
  - a) ~Harder, Better, Faster, Stronger~
  - a) smaller
  - b) tree shakable by plugins 
  - c) have a nice API 


## Thank you

For this loooong read and by the tradition:

No date-fns maintainers were harmed in the making of this article 😉