The best JavaScript date libraries in 2021
Tags: javascript, webdev, codepen
Published: 2021-02-16 15:28:33

---
title: The best JavaScript date libraries in 2021
published: true
description: The best JavaScript date libraries, with interactive code examples and detailed analysis of performance, architecture, and usability
tags: javascript, webdev, codepen 
cover_image: https://www.skypack.dev/blog/wp-content/uploads/2021/02/Best-javascript-date-libraries-2048x1152.png
canonical_url: https://www.skypack.dev/blog/2021/02/the-best-javascript-date-libraries/
---
<p>Wrangling dates and times in JavaScript can be a headache. JavaScript date libraries provide user-friendly APIs and useful utilities that alleviate some of that pain. But with so many options how do you pick the best one? In this post we delve into the world of JavaScript date libraries to help you choose. Our top pick, <strong>date-fns</strong>, delivers the best feature set combined with an elegant modular architecture.</p>
<h2 id="our-picks">Our picks</h2>
<h3 id="best-overall-date-fns">Best overall: <a href="https://www.skypack.dev/view/date-fns">date-fns</a></h3>
<p><strong>date-fns</strong> offers great documentation, functional architecture, and utilities that handle almost any task you can think of. If dates are a critical concern for your JavaScript application, use <strong>date-fns.</strong> Each feature has clear documentation written in ESM (ES Modules) for the browser. Logical and consistent function names encourage readable code. A modular architecture allows build tools to trim away unused code for a slimmer final build.</p>
<h3 id="best-for-time-zones-luxon">Best for time zones: <a href="https://www.skypack.dev/view/luxon">Luxon</a></h3>
<p>If time zones or localization are your primary concern, we recommend <strong>Luxon</strong>. <strong>Luxon</strong> leverages JavaScript's <code>Intl</code> for speed and slimness while providing what <code>Intl</code> doesn't: an immutable user-friendly API. Concise, well-written documentation eases the learning curve for getting started. </p>
<h3 id="best-minimalist-option-dayjs">Best minimalist option: <a href="https://www.skypack.dev/view/dayjs">Day.js</a></h3>
<p>For basic handling of dates, <strong>Day.js</strong> is a minimalist library that offers an excellent API without much overhead. While <strong>Day.js</strong> has fewer features than <strong>Luxon</strong> or <strong>date-fns</strong>, it's much smaller in size. </p>
<div class="TOC">
<h2>The Research</h2>
<ul>
<li><a href="#when-to-use-a-datetime-package">When to use a JavaScript date library</a></li>
<li><a href="#our-previous-pick-momentjs">Our previous pick: Moment.js</a></li>
<li><a href="#how-we-picked">How we picked</a></li>
<li><a href="#our-picks-in-detail">Our picks in detail</a>
<ul>
<li><a href="#date-fns">Date-fns</a></li>
<li><a href="#dayjs">Day.js</a></li>
<li><a href="#luxon">Luxon</a></li>
</ul>
</li>
<li><a href="#other-datetime-packages">Other JavaScript date libraries</a></li>
<li><a href="#useful-resources">Useful Resources</a></li>
</ul>
</div>
<h2 id="when-to-use-a-datetime-package">When to use a JavaScript date library</h2>
<p>Why not just use JavaScript's built-in <strong>Date</strong> object? A good JavaScript date library provides a clear advantage over JavaScript's <strong>Date</strong> in several ways: immutability, parsing, and time zones. In addition, JavaScript date libraries offer useful utilities for date manipulation and formatting, which can save developers time and energy.</p>

> ℹ️ Maggie Pint's blog post <a href="https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/">Fixing JavaScript Date</a> describes how Javascript's <strong>Date</strong> was based on a <em>Java</em> (nope, not a typo) API from the 1990s. That Java API is long gone from Java but its problems live on in JavaScript's <strong>Date</strong>.</p>

<p>JavaScript's <strong>Date</strong> is mutable, which can lead to unintentional bugs. Let's say you create a <strong>Date</strong> object named <code>currentTime</code>. You display it on top of the website. Another developer comes in and wants to create a widget that displays next weeks events. They use <code>currentTime.setDate(currentTime.getDate() + 7)</code> at the top to the widget to display next week's date. However it also changes the date in the header! Oops. With an immutable date library, adding a week would create a new instance so the original would not change.</p>
<p>While <strong>Date</strong> has a <code>parse</code> method, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date">MDN documentation for <strong>Date</strong>'s <code>dateString</code> notes</a> that usage is "strongly discouraged." An excellent answer in the Stack Exchange question <a href="https://stackoverflow.com/a/20463521">Why does Date.parse give incorrect results?</a> describes in detail differences in formatting standards and browsers lead to inconsistent and unreliable results. If you need to parse, a date library is a must.</p>
> <p>ℹ️ <a href="https://zachholman.com/talk/utc-is-enough-for-everyone-right">UTC is enough for everyone..right?</a> is an incredible interactive presentation by Zach Holman on how dates work in programming</p>

<p>Time zones are another major frustration. <strong>Date</strong> in the browser always represents the local system date stored as milliseconds since January 1st, 1970 in UTC. A <strong>Date</strong> can rendered as a <code>string</code> in a different time zone using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl"><strong>Intl</strong></a>, but the <strong>Date</strong> itself is always the local system time.</p>
<p><strong>Date</strong> also lacks utilities for common tasks like creating human-readable relative dates. Using library utilities for such tasks can save a lot of time.</p>
 
> <p>ℹ️ TC39, the major JavaScript standard's committee, is working on a new modern API called Temporal (<a href="https://github.com/tc39/proposal-temporal">see the proposal here</a>) that solves all of the above issues. <a href="https://medium.com/better-programming/the-future-of-date-and-time-in-javascript-e1772c7976c">The Future of Date and Time in JavaScript</a> by Christofer Eliasson is an excellent read of the history behind Temporal and what it means for JavaScript.

<p>In the meantime, be aware of the limitations of <strong>Date</strong> and use a library when you need one.</p>
<h2 id="our-previous-pick-momentjs">Our previous pick: Moment.js</h2>
<p>For a long time <strong>Moment.js</strong> was king of the JavaScript date libraries, but in 2020 <strong>Moment.js</strong>'s maintainers published a <a href="https://momentjs.com/docs/#/-project-status">Project Status</a> announcing they consider Moment.js a legacy project. </p>
<p>The maintainers argued that there was no way to refactor <strong>Moment.js</strong> to meet the demands of modern JavaScript development such as immutability and tree shaking. Lighthouse (Chrome's built-in auditing tool) warns against using Moment because of its large size (329 kb).</p>
<p>For these reasons, we do not include it as one of our recommended picks. If you are looking for a replacement to <strong>Moment.js</strong> that closely matches its API, try <strong>Day.js</strong>.</p>
<h2 id="how-we-picked">How we picked</h2>
<p>We looked at data from <a href="https://www.skypack.dev/">Skypack</a> and <a href="https://www.npmtrends.com/">NPM trends</a> to identity the most popular and trending libraries and evaluated them against these core criteria:</p>
<ul>
<li><strong>Browser-friendly</strong>: We evaluated JavaScript date libraries for use directly by the browser rather than the Node.js backend.</li>
<li><strong>Great documentation</strong>: Users look to this to implement the library correctly. We looked at the parts the facilitate this process: organization, search, examples, and the individual pages relating to the methods we tested.</li>
<li><strong>Modularity + Tree shaking</strong>: Modular architecture allows you to shrink your library size by "tree-shaking" out any library code you're not using. Common build tools capable of tree-shaking include <a href="https://webpack.js.org/">Webpack</a>, <a href="https://snowpack.dev/">Snowpack</a> and <a href="https://rollupjs.org">Rollup</a>.</li>
<li><strong>Features</strong>: Feature-richness was just one factor. We also considered whether a library was especially good at certain tasks.</li>
<li><strong>Performance</strong>: Measuring performance gives us a clue at how fast each library performs common operations. This usually isn't noticeable but in large, complex apps can cause lag.</li>
<li><strong>Size</strong>: One of the biggest problems people had with <strong>Moment.js</strong> was size. A large library can substantially increase page load times.</li>
<li><strong>Anti-bug features</strong>: Immutability, readability, and informative error messages can help prevent bugs. When code is readable, you can learn a lot about what it does by reading it. Format, syntax, and naming conventions can make all the difference in readability.</li>
</ul>
<h3 id="how-we-tested">How we tested</h3>
<p>When evaluating each library we made a CodePen using Skypack. We attempted to pick out common use cases that illustrate differences between libraries:</p>
<ul>
<li>Rendering the current date &amp; time</li>
<li>Rendering the current date using a custom format</li>
<li>Modifying a date to add/remove time</li>
<li>Working with timezones</li>
<li>Parsing arbitrary date strings</li>
</ul>
<p>First we implemented these cases using JavaScript's <strong>Date:</strong></p>
{% codepen https://codepen.io/melissamcewen/pen/NWRMoLm %}

<p>We wrote up examples for performance testing on <a href="https://perf.link/">perf.link</a> and all of the tests and code are available in the <a href="https://github.com/melissamcewen/date-time-perf-examples/">Date/time performance examples GitHub repository</a>. If you have a specific use-case, you can modify one of the provided examples. JavaScript date libraries contain hundreds of methods and features that we couldn't test them all. Instead, we opted to test the same methods demonstrated in our Codepens.</p>
<img class="wp-image-79 size-large" src="https://www.skypack.dev/blog/wp-content/uploads/2021/02/testing-performance-perf-link-skypack-javascript-date-library-1024x559.jpg" alt="A code block imports all the tested libraries via Skypack, then there are four blocks showing code for adding a week to a date using each JavaScript date library. The results are 1,990 ops/s Luxon, 25,495 ops/s Day.js, 817,780 ops/s JavaScript native date, 217,296 ops/s date-fns" width="1024" height="559" /> 
<p><a href="https://codepen.io/melissamcewen/pen/YzGMyyd">A chart of the performance data is also available on CodePen</a>. The data  doesn't indicate a clear advantage for any one library. Each JavaScript date library implements different features differently, so that's not surprising.</p>
> <p>⏱ For other performance comparisons see</p>
<ul>
<li><a href="https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js">Why you shouldn't use Moment.js...</a></li>
<li><a href="https://github.com/you-dont-need/You-Dont-Need-Momentjs">You don't (may not) need Moment.js</a></li>
</ul>

<p>The sizes listed on each review are based on loading via the Skypack CDN. If you're using a build tool to tree-shake and the library is tree-shakable (like <strong>date-fns</strong>), the size will depend on what parts you use. For evaluating libraries with tree-shaking we recommend <a href="https://bundlephobia.com/">Bundlephobia.</a></p>
<p>A caveat to our testing is we did not consider back-end <code>Node.js</code> use. Many JavaScript date libraries rely on browser APIs so may not work correctly on the back-end.</p>
<h4 id="other-cases-to-test">Other cases to test</h4>
<p>Depending on your needs there are lots of other tests you could do. If you'd like to test other features not covered here, you can make changes to any of the examples in our embedded Codepens or <a href="https://codepen.io/collection/DKYbjR">CodePen date collection</a>.</p>
<p>For example:</p>
<ul>
<li>Does it let us know if we have an invalid date when we pass in invalid items? For example moment(undefined) behaves like moment() and doesn't output an error, which could lead to bugs.</li>
<li>How well does it handle different languages and locales?</li>
<li>Can it render relative dates (like "4 days ago")? Can it do this in different languages?</li>
<li>Does it work in older browsers?</li>
</ul>
<h2 id="our-picks-in-detail">Our picks in detail</h2>
<h3 id="date-fns"><a href="https://www.skypack.dev/view/date-fns">Date-fns</a></h3>
<p>Size: 58.9 kb (tree-shakable)</p>
{% codepen https://codepen.io/melissamcewen/pen/bGwjaGV %}

<p><strong>date-fns</strong> is a pleasure to use, offering all the benefits of a modular architecture and covering almost any date use case. Our example shows the power of good naming and syntax in conveying information. Code like <code>add(now, {days: 7})</code> is straightforward to understand even if you're unfamiliar with <strong>date-fns</strong>.</p>
<p>To get the most out of <strong>date-fns'</strong>s modular architecture, use a tree-shaking build tool (see our criteria section) and import only the features you need:</p>
<pre><code>import { format, add, getHours, parse } from "https://cdn.skypack.dev/date-fns@2.16.1";
</code></pre>
<p>In the example above, a tree-shaking build tool would remove all code from <strong>date-fns</strong> that's not used in <code>format</code>, <code>add</code>, <code>getHours</code>, or <code>parse</code>. The final build would be much slimmer. Still at 58.9kb for the whole package, it's not giant in the first place.</p>
<p><strong>date-fns</strong> doesn't package a browser build for NPM (<a href="https://github.com/date-fns/date-fns/issues/1780">see the related GitHub issue</a>) and therefore only works on CDNs that transform for the browser like <a href="https://www.skypack.dev/">Skypack</a> and <a href="https://www.jsdelivr.com/esm">ESM.run</a>. However, documentation has examples labeled for the browser as both ESM(ES Modules) and ES2015. This ensures developers don't get confused trying to run <code>Node.js</code> backend code in the browser.</p>
<h4 id="limitations">Limitations</h4>
<p>Although we liked almost everything about <strong>date-fns</strong>, it is not for everyone. For starters, <strong>date-fns</strong> seems geared towards experienced developers working with a professional tool chain. Working without a build tool, the tree-shaking advantage disappears.</p>
<p>Note that our CodePen example starts with a <code>const now = new Date()</code>, which is the default JavaScript <strong>Date</strong> object. As noted in our <strong>Date</strong> section a <strong>Date</strong> is always the current system's time zone. <strong>date-fns</strong> has a separate library for working with time zones using helper functions. We found the documentation and examples for these helper functions less consistent than the main <strong>date-fns</strong>. Our resulting code is less readable than the rest of the examples. Our time-zone example for <strong>date-fns</strong> is 4 lines of code, compared to 1 for <strong>Luxon</strong>.</p>
<p>Another quirk we encountered was if you Google "date-fns parse" the top results take you to the <a href="https://date-fns.org/v2.0.0-alpha.9/docs/parse">v2.0.0-alpha docs for parse</a>, which no longer work (the current version is 2.16). We found ourselves using Google because the documentation's built-in search seems to search only title and descriptions of sub-pages. The information architecture of the menu could also use improvement, as we would it overwhelmingly long. On occasion, a modal advertising "Get awesome JavaScript jobs to your email" covered the menu's bottom.</p>
<p>The hardest part of implementing <strong>date-fns</strong> Codepen examples was parsing, since they use different format tokens from other libraries. Furthermore, some tokens are not compatible with other tokens and the compatibility table is a Google doc that is hard to read.</p>
<h3 id="dayjs"><a href="https://www.skypack.dev/view/dayjs">Day.js</a></h3>
<p>Size: 4kb</p>
{% codepen https://codepen.io/melissamcewen/pen/LYRJvNm %}


<p>If <strong>Date</strong> fulfills <strong>almost</strong> all your needs but you don't want to deal with its downsides, <strong>Day.js</strong> is a great choice. <strong>Day.js</strong>'s small size makes it ideal for build-tool free environments like CodePen and plain JS/HTML/CSS projects. If you're forced to support older browsers, <strong>Day.js</strong> 's <a href="https://github.com/iamkun/dayjs">Readme</a> says it supports IE as far back as IE 7, though we did not test these capabilities.</p>
<p>The <strong>Day.js</strong> documentation claims "If you use Moment.js, you already know how to use Day.js", which would make migrating easier. You can see direct comparisons at the excellent <a href="https://github.com/you-dont-need/You-Dont-Need-Momentjs">You don't (may not) need Moment.js</a>. The code in our example CodePen is readable with the exception of the parsing and time zone cases.</p>
<p>A well-organized menu helped us find what we need in the <strong>Day.js</strong> documentation. In addition the documentation search gives great results organized by type. We liked that most documentation pages have example code.</p>
<h4 id="limitations">Limitations</h4>
<p>Like <strong>date-fns</strong>, <strong>Day.js</strong> builds on top of JavaScript's <strong>Date</strong>, so time zone support requires another library. But unlike <strong>date-fns</strong>, <strong>Day.js</strong> relies on a plugin system that we did not find intuitive. You not only need to import the plugin but you also need to enable it by running <code>dayjs.extend(plugin_name)</code>.</p>
<p>There is a stark contrast in our CodePen example between the time zone example and the other examples. The time zone example is much less readable and you'll also notice we commented it out. That's because it gave us incorrect results. It could be because our example time zone is an edge case or we did something wrong, but we attempted to follow the documentation. We recommend <strong>Luxon</strong> instead if you need to deal with time zones.</p>
<p>We encountered a few minor issues in the docs. The documentation does not contain any ESM (Es Modules) examples. This is especially apparent in <a href="https://day.js.org/docs/en/plugin/loading-into-browser">the documentation for loading plugins in the browser</a>, which recommends loading via script tag and then extending via the <code>window</code> global. In general for readability and browser compatibility, we prefer to avoid globals.</p>
<p>Unlike the other libraries you don't indicate a format with tokens when parsing. This worked fine in our CodePen but we wonder how correctly it would handle ambiguous formats. We felt <a href="https://day.js.org/docs/en/parse/parse">the documentation could use more examples, specifically the parsing page</a>. It took us a minute to realize parsing isn't its own method: you use <code>dayjs()</code> and pass in a string. Unfortunately this syntax makes the code less understandable at a glance.</p>
<h3 id="luxon"><a href="https://www.skypack.dev/view/luxon">Luxon</a></h3>
<p>Size: 29.5kb</p>
{% codepen https://codepen.io/melissamcewen/pen/wvzYeNN %}


<p>If time zones are high on your list of concerns, go with <strong>Luxon</strong>. Dealing with time zones is never fun, so it's nice to use a library where it just works. Most date libraries don't have a built-in time-zone support because adding a time zone database is complex and adds a lot of weight to the final size. To get around this problem, <strong>Luxon</strong> hacks into JavaScript's <code>Intl</code> API, which most browsers support. It's the only JavaScript date library we evaluated that does not extend <strong>Date</strong>, instead using its own <code>DateTime</code> class. In our experience this makes working with time zones less bug-prone.</p>
<p>Luxon's creator Isaac Cambron is a <strong>Moment.js</strong> maintainer. In <a href="https://moment.github.io/luxon/docs/manual/why.html">Why does Luxon exist</a> he says "Luxon started because I had a bunch of ideas on how to improve Moment but kept finding Moment wasn't a good codebase to explore them with."</p>
<p><strong>Luxon</strong>'s documentation is divided up into a <a href="https://moment.github.io/luxon/docs/manual">Manual</a> and <a href="https://moment.github.io/luxon/docs/identifiers.html">Reference</a>. Since the more technical API documentation is in the <a href="https://moment.github.io/luxon/docs/identifiers.html">Reference</a>, the <a href="https://moment.github.io/luxon/docs/manual">Manual</a> is much more readable. Most importantly the <a href="https://moment.github.io/luxon/docs/manual">Manual</a> is well-written and organized into clear sections, with browser-friendly install instructions for ESM (ES Modules). The resulting code in our CodePen example is remarkably readable, particularly for the time zone case.</p>

> <p>ℹ️ "Can't we just get rid of time zones?" A common developer refrain, usually after dealing with a time zone related bug. <a href="https://qntm.org/abolish">So You Want To Abolish Time Zones</a> is a great read on why that's not a panacea.</p>

<h4 id="limitations">Limitations</h4>
<p>We recommend <strong>date-fns</strong> for date dependent applications because compared to <strong>Luxon</strong> it has a larger feature set and is tree-shakable. If feature set is not a major concern, <strong>Day.js</strong> is a better pick because it's ~7 times smaller than <strong>Luxon</strong> (29.5kb for <strong>Luxon</strong> vs. 4kb for <strong>Day.js</strong>). Except for time zones, <strong>Luxon</strong> doesn't offer a clear advantage.</p>
<p>We noted above that <strong>Luxon</strong> relies on <code>Intl</code> and that <strong>most</strong> browsers support it, but this doesn't include older browsers. <a href="https://moment.github.io/luxon/docs/manual/matrix.html">A polyfill</a> is available, but this will increase the complexity and size of using <strong>Luxon</strong>.</p>
<p>A minor quibble is <strong>Luxon</strong>'s documentation search doesn't seem to index the entire text.</p>
<h2 id="other-datetime-packages">Other JavaScript date libraries</h2>
<p>Here are two interesting JavaScript date libraries that we didn't have time to evaluate:</p>
<ul>
<li><a href="https://www.skypack.dev/view/date-and-time">date-and-time</a></li>
<li><a href="https://www.skypack.dev/view/@js-joda/core">js-Joda</a></li>
</ul>
<h2 id="useful-resources">Useful Resources</h2>
<ul>
<li><a href="https://exploringjs.com/impatient-js/ch_dates.html">JavaScript for impatient programmers (ES2020 edition): Dates</a></li>
<li><a href="https://zachholman.com/talk/utc-is-enough-for-everyone-right">UTC is Enough for Everyone, Right?</a></li>
<li><a href="https://medium.com/better-programming/the-future-of-date-and-time-in-javascript-e1772c7976c">The Future of Date and Time in JavaScript | by Christofer Eliasson | Better Programming | Medium</a></li>
<li><a href="https://github.com/you-dont-need/You-Dont-Need-Momentjs">you-dont-need/You-Dont-Need-Momentjs: List of functions which you can use to replace moment.js + ESLint Plugin</a></li>
<li><a href="https://blog.logrocket.com/4-alternatives-to-moment-js-for-internationalizing-dates/">4 alternatives to Moment.js for internationalizing dates - LogRocket Blog</a></li>
</ul>