date-fns leaves the Date object alone, which is the whole design
⏳ Modern JavaScript date utility library ⌛️
At a glance
- What is it?
- A TypeScript date library of 200 or more pure functions over the native Date, positioned as Lodash for dates, with tree-shaking as the reason the API is one function per module. Time zone support arrived in v4.0, v5 is in alpha, and the repository states its licence in the README rather than in a file.
- Who is it for?
- Adopt date-fns if you want named, tree-shakeable date functions that do not monkey-patch the Date prototype, and if your dates cross time zones now or will soon. Do not adopt it on the assumption that v5 is safe, because v5.0.0 is still an alpha published on the same day as v4.4.0.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It never touches the Date object, and that is the point
Two of the listed properties are the same decision seen from opposite sides, and together they are the reason to choose this over a date plugin. Native dates means the library uses the existing native type and does not extend core objects, explicitly for safety's sake. Immutable and pure means the functions are built as pure functions and always return a new date instance. So there is no patching of Date.prototype anywhere, which means no risk of a third-party dependency changing the behaviour of unrelated code, and it also means every call is an assignment. A reader migrating from a mutating style needs to know that the return value is the result, because writing format(myDate, 'yyyy') and expecting myDate to change simply does nothing. The alternative design, extending the prototype, is the one the project explicitly rejects.
One function per module is a tree-shaking requirement
The library ships 200 or more functions, and the way that number stays affordable in a browser bundle is the modular claim: pick what you need, and it works with webpack, Browserify or Rollup and supports tree-shaking. That combination explains a design choice that otherwise looks fussy. A 200-function single module would be unusable at web scale, so the package is structured so that importing format and compareAsc pulls in only those two and their dependencies. The cost is on the reader, and it is a real discipline rather than a formality. The functions are used as named imports, and a bundler can only drop what it can see being unused, so default-importing a namespace to save typing at three call sites is the way to accidentally ship the whole library. The example in the project makes the intended shape explicit, importing by name at the top of the file.
A wrong format token gives you a plausible wrong string
Formatting is the most-used feature and the easiest to misuse, and the example shows the shape of the problem. The token string is passed as an ordinary string:
import { compareAsc, format } from "date-fns";
format(new Date(2014, 1, 11), "yyyy-MM-dd");
//=> '2014-02-11'Nothing in that call throws if a token is wrong, and nothing warns you, because the tokens are replaced by substitution rather than parsed as a format. The four-digit year here is written in lowercase, and the token vocabulary is documented on the site rather than in the package, so the failure mode of a typo is a string that looks like a date and is not one. That is a category of bug which survives code review and unit tests written by the same person who chose the token. The mitigation is unglamorous: keep the format strings in one module, and test a few known timestamps against literal expected output rather than snapshotting whatever the library returned.
Time zones arrived in v4.0 and v5 is still an alpha
The current state of the version line is the thing to read before pinning. The most recent releases listed are v4.4.0 and v5.0.0-alpha.0, both published on 2026-05-29, with v4.3.0 on 2026-05-22. Two releases on the same day, one of them a major-version alpha, means the v5 line is being shaped in public while v4.4 is the stable one. The headline feature of the v4 line is first-class time zone support, announced with a post on the project blog, which is the substantive change since the earlier 2.x era. The practical advice is to depend on the v4 line and treat v5 as something to evaluate rather than adopt, since an alpha of a library with 200 functions can still change signatures. Note also that the repository is not archived and the last push was on 2026-09-22, so the alpha is not a sign of abandonment.
The repository is a pnpm monorepo that has moved to Oxc
The tooling tells you something about the project's direction. The root package is @date-fns/root, private and versioned 0.0.0, which is the workspace-root convention, and the real packages live under pkgs/ with a pnpm-workspace.yaml and a pnpm-lock.yaml. The development dependencies are unusual and worth noticing: oxfmt, oxlint and oxlint-tsgolint rather than Prettier and ESLint, alongside TypeScript 7.0.2 and Vitest 5.0.1. So the linting and formatting have moved to the Oxc toolchain, and the test runner is well past the versions most projects still pin. There is also a codemods/ directory, which matters more than it looks: a 200-function API is only upgradeable if the major migrations can be automated, and shipping codemods is the project telling you it expects to keep making them. The tree also carries mise.toml, an .nvmrc, a devcontainer definition and an .mcp.json.
The licence is in the README and the LICENSE file is not in the tree
The licence is stated at the bottom of the README as MIT, attributed to Sasha Koss, linking to a generated licence page rather than to a file. The repository root does not appear to contain a LICENSE file: the top-level entries listed are configuration directories, documentation files, the monorepo configuration and the source directories, and no licence file is among them. That is consistent with the repository's licence field being recorded as unrecognised rather than as MIT, since a machine reading a standard identifier would find nothing. This is a small point and almost certainly an oversight rather than a decision, but it has a practical effect. An automated licence check, or a legal review that looks for the file, will come back empty, and the answer has to come from the README. If the distinction matters to you, raise it as an issue; the project accepts contributions and the fix is trivial.
Locales and types are part of the product, not an afterthought
Two claims in the feature list do real work for a library this widely embedded. I18n means dozens of locales, with the instruction to include only what you need, which is the same tree-shaking discipline applied to language data. A date library that formats in English while the rest of the product is localised is a bug waiting for a customer in a market where day-first versus month-first ordering differs, and the ordering difference in particular is the kind of mistake a formatter hides unless you test it. TypeScript is described as 100 percent with handcrafted types rather than generated ones, which for a date library means the branded argument and return types are written by the authors, and handcrafted types are the difference between a function that accepts a Date and one that accepts a Date and will not silently accept a number. The stated scope is a browser and Node.js, with the API described as consistent across the two.
Editorial conclusion
Adopt date-fns if you want named, tree-shakeable date functions that do not monkey-patch the Date prototype, and if your dates cross time zones now or will soon. Do not adopt it on the assumption that v5 is safe, because v5.0.0 is still an alpha published on the same day as v4.4.0. Verify first which major version your dependency resolves to, read the format token table before trusting a formatted string, and note that there is no LICENSE file at the repository root even though the README names MIT, so point your compliance tooling at the README rather than searching for a file that is not there.
Frequently asked questions
Why use date-fns?
It offers 200 or more functions over the native Date type without extending core objects, built as pure functions that always return a new date instance, and it is modular so a bundler can tree-shake away what you do not import. It also ships dozens of locales you can include selectively.
how to install date fns
With npm install date-fns --save. The library is published as an npm package, and it works in both a browser and Node.js, with bundler support for webpack, Browserify and Rollup.
format date using date-fns
Import the format function by name and pass a Date and a token string, for example format(new Date(2014, 1, 11), "yyyy-MM-dd") returning '2014-02-11'. Nothing throws on a wrong token, so test formatted output against literal expectations.
what is date fns tz
First-class time zone support is the headline feature of date-fns v4.0, announced in a post on the project blog. It arrived after the 2.x line, so older guides and blog posts about handling zones in date-fns predate it.
is date fns deprecated
No. The repository is not archived and the last push was on 2026-09-22, with v4.4.0 published on 2026-05-29. A v5.0.0-alpha.0 shipped the same day, so the v5 line is in alpha while v4.4 is the stable release to depend on.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/date-fns-date-fns)