@js-joda/core vs date-fns vs luxon
Modern Date and Time Handling in JavaScript
@js-joda/coredate-fnsluxonSimilar Packages:

Modern Date and Time Handling in JavaScript

@js-joda/core, date-fns, and luxon are the leading libraries for managing dates in JavaScript, each solving the pitfalls of the native Date object. date-fns offers a functional, modular approach ideal for tree-shaking. luxon provides an immutable, class-based API with built-in time zone support. @js-joda/core brings Java-style strict immutability and domain modeling to the browser.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@js-joda/core01,6647.75 MB112 months agoBSD-3-Clause
date-fns0-10.9 MB-4 months agoMIT
luxon016,4614.59 MB188a year agoMIT

@js-joda/core vs date-fns vs luxon: Architecture and API Compared

Handling dates in JavaScript is notoriously difficult. The native Date object is mutable, lacks time zone support, and has a confusing API. @js-joda/core, date-fns, and luxon solve these problems differently. Let's compare how they tackle common engineering challenges.

šŸ—ļø Core Philosophy: Functions vs Classes

date-fns treats dates as data, not objects.

  • You pass a date into a function.
  • The function returns a new date.
  • No prototype chaining or class inheritance.
// date-fns: Functional approach
import { addDays, format } from 'date-fns';

const date = new Date();
const nextWeek = addDays(date, 7);
console.log(format(nextWeek, 'yyyy-MM-dd'));

luxon uses immutable classes.

  • You create a DateTime object.
  • Methods return new instances instead of changing this.
  • Feels like modern OOP without the mutation risks.
// luxon: Class-based immutable
import { DateTime } from 'luxon';

const date = DateTime.now();
const nextWeek = date.plus({ days: 7 });
console.log(nextWeek.toFormat('yyyy-MM-dd'));

@js-joda/core ports Java's Joda-Time to JavaScript.

  • Strictly immutable objects like LocalDate or ZonedDateTime.
  • Separates date, time, and zone concepts strictly.
  • Best for developers coming from Java or C#.
// @js-joda/core: Strict immutability
import { LocalDate } from '@js-joda/core';

const date = LocalDate.now();
const nextWeek = date.plusDays(7);
console.log(date.toString());

šŸŒ Time Zone Support: Built-in vs Add-ons

luxon has time zones built into the core.

  • Uses the Intl API under the hood.
  • No extra packages needed for basic zone switching.
  • Great for displaying times in user's local zone.
// luxon: Built-in time zones
import { DateTime } from 'luxon';

const nyTime = DateTime.now().setZone('America/New_York');
const tokyoTime = nyTime.setZone('Asia/Tokyo');

date-fns requires an add-on for time zones.

  • Core library is zone-agnostic.
  • You must install date-fns-tz separately.
  • Keeps the core bundle small if you don't need zones.
// date-fns: Requires date-fns-tz
import { zonedTimeToFormat } from 'date-fns-tz';

const date = new Date();
const nyString = zonedTimeToFormat(date, 'yyyy-MM-dd HH:mm', { timeZone: 'America/New_York' });

@js-joda/core separates time zones into a plugin.

  • Core handles logic; @js-joda/timezone handles data.
  • Very precise control over zone rules.
  • Heavier setup but extremely reliable for complex logic.
// @js-joda/core: Requires @js-joda/timezone
import { ZonedDateTime, ZoneId } from '@js-joda/core';
import '@js-joda/timezone'; // Loads zone data

const zdt = ZonedDateTime.now(ZoneId.of('America/New_York'));

šŸ“ Parsing and Formatting: Flexibility vs Strictness

date-fns uses tokens similar to Moment.js.

  • Very flexible pattern strings (e.g., yyyy-MM-dd).
  • parse function requires a reference date for relative values.
  • Great for user-facing input where format varies.
// date-fns: Flexible parsing
import { parse } from 'date-fns';

const input = '2023-10-01';
const date = parse(input, 'yyyy-MM-dd', new Date());

luxon prefers ISO strings and explicit tokens.

  • fromISO is the default for parsing.
  • Custom parsing requires fromFormat.
  • Stricter by default, which reduces bugs.
// luxon: Strict ISO default
import { DateTime } from 'luxon';

const date = DateTime.fromISO('2023-10-01');
// Custom format
const custom = DateTime.fromFormat('01/10/2023', 'dd/MM/yyyy');

@js-joda/core requires explicit formatters.

  • No magic string parsing.
  • You define a DateTimeFormatter pattern.
  • Highest safety against ambiguous dates.
// @js-joda/core: Explicit formatter
import { LocalDate, DateTimeFormatter } from '@js-joda/core';

const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd');
const date = LocalDate.parse('2023-10-01', formatter);

šŸ“¦ Bundle Strategy: Modular vs Monolithic

date-fns is fully tree-shakable.

  • Import only the functions you use.
  • No global namespace pollution.
  • Ideal for frontend apps where bundle size matters.
// date-fns: Tree-shaking
import { addDays } from 'date-fns'; // Only imports addDays

luxon is a single class entry point.

  • You import DateTime and get all methods attached.
  • Tree-shaking works at the class level, not method level.
  • Slightly larger baseline but convenient.
// luxon: Class import
import { DateTime } from 'luxon'; // Imports whole class

@js-joda/core is modular but verbose.

  • You import specific classes (LocalDate, Instant).
  • Good tree-shaking support.
  • Can feel verbose for simple scripts.
// @js-joda/core: Specific classes
import { LocalDate } from '@js-joda/core';

šŸ¤ Similarities: Shared Ground

While they differ in API style, all three solve the same core problems.

1. 🚫 Immutability

  • None of them mutate the original date object.
  • Prevents hard-to-track bugs in state management.
// All three: Original date remains unchanged
// date-fns
const original = new Date();
const modified = addDays(original, 1); 

// luxon
const original = DateTime.now();
const modified = original.plus({ days: 1 });

// @js-joda/core
const original = LocalDate.now();
const modified = original.plusDays(1);

2. 🌐 UTC and Local Time

  • All distinguish between UTC and system local time.
  • Critical for storing timestamps in databases.
// All three: UTC handling
// date-fns
import { utcToZonedTime } from 'date-fns-tz';

// luxon
DateTime.utc();

// @js-joda/core
import { Instant } from '@js-joda/core';
Instant.now();

3. āœ… Type Safety

  • All ship with TypeScript definitions.
  • Helps catch errors during development.
// All support TypeScript
// date-fns
import { addDays } from 'date-fns';
addDays(new Date(), 1);

// luxon
import { DateTime } from 'luxon';
DateTime.now();

// @js-joda/core
import { LocalDate } from '@js-joda/core';
LocalDate.now();

šŸ“Š Summary: Key Differences

Featuredate-fnsluxon@js-joda/core
Style🧩 FunctionalšŸ›ļø Class-basedā˜• Java Port
Time ZonesšŸ”Œ Add-on (date-fns-tz)āœ… Built-inšŸ”Œ Add-on (@js-joda/timezone)
ParsingšŸ“ Flexible PatternsšŸ›”ļø Strict ISOšŸ›”ļø Explicit Formatters
BundlešŸƒ Highly ModularšŸ“¦ Class-basedšŸ“¦ Class-based
Learning Curve🟢 Low🟔 MediumšŸ”“ High

šŸ’” The Big Picture

date-fns is the pragmatic choice for most frontend teams. šŸ› ļø It fits naturally into React or Vue workflows where functions are preferred over classes. The modular design keeps bundles small, and the API is easy to learn. Choose this for dashboards, forms, and general UI date display.

luxon is the modern successor to Moment.js. šŸ•°ļø It offers the best balance of power and usability. The built-in time zone support saves you from managing extra dependencies. Choose this for apps that deal heavily with international users and complex time zone conversions.

@js-joda/core is for strict domain logic. āš™ļø It brings backend-grade reliability to JavaScript. If your team knows Java or needs to share date logic between Java backends and JS frontends, this is the tool. Choose this for financial systems or complex scheduling engines.

Final Thought: All three libraries are vastly superior to the native Date object. The choice depends on whether you prefer functions (date-fns), classes with built-in TZ (luxon), or strict domain modeling (@js-joda/core).

How to Choose: @js-joda/core vs date-fns vs luxon

  • @js-joda/core:

    Choose @js-joda/core if you need strict domain modeling similar to Java's Joda-Time. It is ideal for financial systems or complex scheduling where date logic must be precise and shareable with a Java backend. Be aware that it requires extra plugins for time zone support, which adds to the setup complexity.

  • date-fns:

    Choose date-fns if you prefer a functional programming style with a small bundle size. It works well in modern frontend frameworks like React or Vue where you want to import only what you use. This library is best for general UI date formatting and simple manipulations without heavy time zone requirements.

  • luxon:

    Choose luxon if you want a modern, class-based API with built-in time zone support. It is the best replacement for Moment.js and handles internationalization out of the box. This package is suitable for applications that display times across multiple regions without needing extra dependencies.

README for @js-joda/core

Immutable date and time library for JavaScript

npm version GH Actions Build Status Coverage Status Downloads/Month

Introduction

js-joda is an immutable date and time library for JavaScript. It provides a simple, domain-driven and clean API based on the ISO calendar system, which is the de facto world calendar following the proleptic Gregorian rules.

  • js-joda has a lightweight footprint, only 43 kB minified and compressed, no third party dependencies.

  • js-joda is fast. It is about 2 to 10 times faster than other JavaScript date libraries.

  • js-joda comes with built-in parsers/ formatters for ISO 8601 as specified in RFC 3339, that can be easily customized.

  • js-joda supports ECMAScript 5 browsers down to IE11.

  • js-joda is a port of the threeten backport, which is the base for JSR-310 implementation of the Java SE 8 java.time package. Threeten is inspired by Joda-Time, having similar concepts and the same author.

  • js-joda is robust and stable. We ported more then 1700 test-cases with a lots of test-permutations from the threetenbp project. We run the automated karma test-suite against Firefox, Chrome, Node and phantomjs.

Why yet another JavaScript date and time library?

  • Popular JavaScript date libraries like moment or date-utils are wrappers around the native JavaScript Date object, providing syntactic sugar. The native Date object always consist of a date, time and a timezone part. In contrast, js-joda is a standalone date and time implementation.

  • The API has a domain-driven design with classes for each of the different use cases, like LocalDate, ZonedDateTime or Period. For example, LocalDate allows you to handle dates without times (like birthdays or holidays) in a clean and error-safe way, especially if these dates are persisted to an external server.

  • js-joda is immutable. Immutability aligns well with pure functions and with the architecture of frameworks like React and Flux.

The ThreeTen domain models

Dates and Times

  • LocalDate represents a date without a time and timezone in the ISO-8601 calendar system, such as 2007-12-24.

  • LocalTime represents a time without timezone in the ISO-8601 calendar system such as '11:55:00'.

  • LocalDateTime is a description of the date (LocalDate), as used for birthdays, combined with the local time (LocalTime) as seen on a wall clock.

  • ZonedDateTime is a date-time with a timezone in the ISO-8601 calendar system, such as 2007-12-24T16:15:30+01:00 UTC+01:00.

  • Instant is an instantaneous point on the time-line measured from the epoch of 1970-01-01T00:00:00Z in epoch-seconds and nanosecond-of-second.

Duration and Period

  • Duration is a time-based amount of time, such as '34.5 seconds'.

  • Period is a date-based amount of time in the ISO-8601 calendar system, such as '2 years, 3 months and 4 days'.

Additional value types

  • Year represents a year in the ISO-8601 calendar system, such as '2016'.

  • YearMonth represents a year and a month in the ISO-8601 calendar system, such as '2016-01'.

  • Month represents a month-of-year in the ISO-8601 calendar system, such as 'July'.

  • MonthDay represents a month-day in the ISO-8601 calendar system, such as '--12-03'. Could be used to represent e.g. Birthdays.

  • DayOfWeek represents a day-of-week in the ISO-8601 calendar system, such as 'Tuesday'.

Getting started

Node

Install joda using npm

npm install @js-joda/core

Then require it to any module

var LocalDate = require('@js-joda/core').LocalDate;

var d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); // 2013-02-24T00:00:00

Browser

To use js-joda from a browser, download either dist/js-joda.min.js or dist/js-joda.js (with sourcemaps for development). Then add it as a script tag to your page

<script src="js-joda.min.js"></script>
<script>
    var LocalDate = JSJoda.LocalDate;
    var d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); // 2013-02-24T00:00:00
</script>

js-joda packages

js-joda consist of four packages:

package namedescriptionpath
@js-joda/coreImplementation of the ThreeTen Classes and API/packages/core
@js-joda/timezoneImplementation of timezone calculation based on the iana Time Zone Database/packages/timezone
@js-joda/localeImplementation of locale specific functionality for js-joda, especially for formatting and parsing locale specific dates/packages/locale
@js-joda/extraImplementation of the ThreeTen-Extra Classes and API/packages/extra

The @js-joda/examples package is for testing the different build artifacts in different context, like webpack, browser node, etc.

Documentation

Contributing

Contributions are always welcome. Before contributing please read the code of conduct & search the issue tracker. We use GitHub issues. Your issue may have already been discussed or fixed. To contribute, fork js-joda, commit your changes, & send a pull request.

By contributing to js-joda, you agree that your contributions will be licensed under its BSD license.

Note that only pull requests and issues that match the threeten backport API will be considered. Additional requested features will be rejected.

License

  • js-joda is released under the BSD 3-clause license.

  • js-joda uses the ThreeTen-Backport implementation (http://www.threeten.org/threetenbp/) as a reference base for implementation. This allows us to release js-joda under the BSD License while the OpenJDK java.time implementation is under GNU GPL+linking exception. The API of the ThreeTen-Backport is mostly identical to the official Java SE 8 API from the view of our JavaScript port.

  • Our implementation reference base ThreeTen-Backport (http://www.threeten.org/threetenbp/) is also released under the BSD 3-clause license

  • OpenJDK is under GNU GPL+linking exception.

  • The author of Joda-Time and the lead architect of the JSR-310 is Stephen Colebourne.

The API of this project (as far as possible with JavaScript), a lot of implementation details and documentation are just copied but never equalled.

Roadmap

Milestone 1: Core domains (reached with version v1.0.0)

  • Support for the domain models LocalDate, LocalDateTime, ZonedDateTime, Instant, Duration and Period converting to and from ISO8601.
  • ZonedDateTime (without support for loading iana timezone databases) currently supports only fixed offsets like UTC or UTC+02:00 and the system default time zone.

Milestone 2: IANA timezone support (reached with version v1.2.0)

  • Add IANA timezone database support to js-joda. Implement handling of daylight saving transitions, mainly in ZonedDateTime.
  • For access to the IANA timezone database, the plugin @js-joda/timezone is required. It provides an implementation of the ZoneRulesProvider and contains the iana timezone database.

Milestone 3: Locale support (reached with v2.0.0 of @js-joda/locale)

  • Add locale support.
  • Extend pattern parser/ formatter for text with locale support.

see the plugin @js-joda/locale

Future Milestones

  • Reduce library size by removing redundant code, especially by refactoring code for formatting/ parsing dates.
  • Increase test coverage (ongoing task)
  • Cleanup documentation (ongoing task)