Library / SDK
moment/luxon avatar
moment/luxon

Luxon: immutable date and time handling in JavaScript

⏱ A library for working with dates and times in JS

16,460 stars803 forksJavaScriptMIT

At a glance

What is it?
Luxon is an MIT-licensed JavaScript library for dates, times, durations and intervals, built on the native Intl API instead of bundled locale or time zone files. It suits new code that needs real time zone math, and it is a poor fit for projects that cannot rely on full ICU data.
Who is it for?
Adopt Luxon for new JavaScript or TypeScript code that needs time zone conversion, duration arithmetic or interval logic, and where the runtime ships full ICU data. Do not adopt it if you are pinned to an old Node build with a small-icu bundle, or if you need a mutable global locale switch that Moment-style code relies on.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 52 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Luxon replaces, and who it is for

Luxon is a library for working with dates and times in JavaScript, published on npm under the name luxon. Its package description calls it an "Immutable date wrapper", and that phrase sets the design: every operation returns a new object rather than mutating the one you called it on. The README lists three core types, DateTime, Duration and Interval, plus an "Immutable, chainable, unambiguous API".

The audience is JavaScript developers who have outgrown the built-in Date object. Date carries no time zone concept beyond the host's local zone and UTC, its month index starts at zero, and its parsing rules are implementation-defined for many string shapes. Luxon gives those developers named types, explicit zones and a formatting layer that goes through Intl. It is also the library Moment's own maintainers point users toward, which is why the repository lives under the moment organization.

The README points to a page titled "Why does Luxon exist?" for the longer argument, and to a "For Moment users" page for people migrating. If you are starting fresh and your only requirement is adding seven days to a timestamp, you do not need this. If you are storing an instant, rendering it in a user's zone, and then computing the end of that local day, you do.

How the DateTime, Duration and Interval types fit together

A DateTime is an instant plus a zone and a locale. The README's opening example chains four operations and shows the shape of the API:

js
DateTime.now().setZone("America/New_York").minus({ weeks: 1 }).endOf("day").toISO();

Read left to right: take the current instant, reinterpret it in a named IANA zone, subtract a Duration object built from a plain object literal, snap to the last moment of that local day, and serialize. Each call returns a new DateTime, so the intermediate values stay valid and you can branch without defensive copying.

Duration is the second type, and it is what makes the arithmetic readable. Instead of passing milliseconds, you pass unit names. Calendar-aware units such as months and years are handled as calendar operations rather than fixed-length offsets, which matters because a month is not a constant number of milliseconds.

Interval is the third type: a half-open span between two DateTimes. It exists so that containment and overlap checks live on a single object rather than being reimplemented in application code. The README does not spell out the full Interval API, so consult the API docs page it links for the exact methods.

The important architectural claim is in the feature list: "Native time zone and Intl support (no locale or tz files)." Luxon does not ship a copy of the IANA database or CLDR locale data. It asks the host runtime for both. That single decision drives most of Luxon's strengths and its sharpest constraint, which I cover below.

Installing Luxon and formatting a date in a named zone

The README does not inline install commands; it links to a download and install page on the documentation site, and the package is published to npm as luxon. The package.json declares conditional exports, so the same package resolves to an ES module or a CommonJS build depending on how it is imported:

json
"exports": {
  ".": {
    "import": "./build/es6/luxon.mjs",
    "require": "./build/node/luxon.js"
  },
  "./package.json": "./package.json"
}

The practical consequence is that a bundler using import gets the .mjs file and a Node process using require gets the CommonJS file. If your build produces a duplicate copy of Luxon in both formats, that exports map is the place to look.

A first real use is to take an instant and reinterpret it in another zone. The README's own example, quoted above, is the pattern to follow: start from a DateTime, call setZone with an IANA identifier, and finish with a serializer such as toISO. The exact method set beyond that is documented on the API docs page the README links, so check there before assuming a helper exists.

What you should see is the same instant expressed twice, once with the offset of the zone you set and once with the offset of the zone you convert to. Zone names are IANA identifiers, and the README's example uses the same form, so a typo produces an invalid DateTime rather than a silent fallback to local time. Check isValid on the result if the input string comes from user data.

The repository also ships a demo, linked from the README, that runs Luxon in a browser page against a global object.

The Intl dependency is the real constraint

Because Luxon delegates zones and locales to the host, its correctness is bounded by the runtime's ICU data. Node builds configured with small-icu carry only English locale data, and the project's own documentation points to the Intl API as the source of zone and locale information rather than shipping its own. On such a runtime, formatting in a non-English locale will not behave as it does on a full-icu build, and the failure is not a thrown error you can catch at startup.

The second limitation is versioning. Zone rules change when governments change them, and Luxon cannot patch that itself. Updating the runtime or its ICU data is the upgrade path, which is a different operational motion than bumping a package version. Teams that pin an old container image inherit old zone rules.

The third is that the API is deliberately not a drop-in for Moment. Immutability means code that mutated a Moment object in place will break, and the README answers this with a dedicated "For Moment users" page plus an upgrading guide for 3.0. If your codebase is large and heavily Moment-shaped, the migration is a real project, not a find-and-replace.

Finally, Luxon is the wrong tool when you need a date library that works identically across every runtime without ICU, or when you need a mutable global locale switch. It is also the wrong tool for a single timestamp format call, where Intl.DateTimeFormat alone is enough.

Luxon compared with Day.js and date-fns

Day.js is the closest alternative in spirit: a small Moment-compatible API with a plugin system, where time zone and advanced formatting live in optional plugins you register explicitly. The difference in approach is where the data lives. Day.js plugins carry their own logic and can be added piece by piece, while Luxon assumes the runtime already knows about zones and locales and calls into it. That makes Luxon smaller to install but more dependent on the host.

date-fns takes a third path: a collection of individual functions, tree-shakeable by design, with no wrapper object and no chain. You import format and addDays separately. Luxon's DateTime is a single object with methods, so you cannot drop the parts you do not use in the same way, but you also do not have to assemble behavior from separate imports.

The honest summary is that the choice is about where complexity sits. Luxon puts it in the runtime's ICU data. Day.js puts it in plugins you opt into. date-fns puts it in your import list. None of these is strictly better; they fail in different places. For a server rendering timestamps for users in many zones on a current Node LTS, Luxon's bet is a good one. For a browser bundle where every kilobyte is contested, a function-per-import library is easier to reason about.

Licence, maintenance and upgrade cost

Luxon is MIT licensed, per the README badge and the LICENSE.md file in the repository root. MIT is permissive: you can use, modify and redistribute it, including in closed-source products, provided the copyright notice and licence text are preserved. That is a description of the licence text, not legal advice; if your organization has a policy review for third-party dependencies, run it through that.

The repository is not archived, and the last push was on 2026-08-09, so work is still landing. The README also announces a road to Luxon 4.0 and links to a discussion thread asking for feedback on the next major version. That is a concrete planning signal: a major release is on the table, and major releases in this library have historically carried migration guides, as the 3.0 upgrading page shows. Budget for reading one when 4.0 ships.

The upgrade cost in normal operation is low, since the package is a single dependency with conditional exports and no peer dependencies listed. The cost that surprises people is environmental rather than programmatic: keeping ICU data current on your runtime so that zone rules and locale formats match reality. In the repository, the version field in package.json reads 3.7.2, and the changelog file at the root is where release history is recorded.

Editorial conclusion

Adopt Luxon for new JavaScript or TypeScript code that needs time zone conversion, duration arithmetic or interval logic, and where the runtime ships full ICU data. Do not adopt it if you are pinned to an old Node build with a small-icu bundle, or if you need a mutable global locale switch that Moment-style code relies on. Before committing, verify three things: that your runtime resolves the correct zone for a DST boundary, that your bundler picks up the ESM entry, and that you have read the 3.0 upgrading guide if you are coming from an earlier major.

Frequently asked questions

What is Luxon used for?

It is a JavaScript library for working with dates and times, offering DateTime, Duration and Interval types with an immutable, chainable API. The README highlights parsing and formatting for common and custom formats, plus native time zone and Intl support with no locale or tz files.

how to install luxon

The README does not list an install command inline; it links to a download and install page on the documentation site, and the package is published on npm under the name luxon. The package.json declares conditional exports, so import resolves to the ES module build and require resolves to the CommonJS build.

how to use luxon in javascript

The README's opening example chains DateTime.now().setZone("America/New_York").minus({ weeks: 1 }).endOf("day").toISO(). Each call returns a new DateTime, so you can branch on intermediate values without copying. The repository also links a browser demo that runs Luxon against a global object.

what is luxon

Luxon is a library for working with dates and times in JavaScript, published on npm under the name luxon. Its package description calls it an "Immutable date wrapper", and the README lists DateTime, Duration and Interval as its core types.

how to use luxon

The README's opening example chains DateTime.now().setZone("America/New_York").minus({ weeks: 1 }).endOf("day").toISO(). The README also links a quick tour, API docs and a browser demo for working through the rest of the API.

how to use luxon js

Import the types you need from the package, as in the README's example that starts from DateTime.now() and chains setZone, minus, endOf and toISO. The package.json exports map sends import to the ES module build and require to the CommonJS build.

Official sources

  1. Issues
  2. License: MIT
  3. moment/luxon on GitHub
  4. Project website
  5. README
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/moment-luxon.svg)](https://hysenlabs.com/projects/moment-luxon)