date-fns vs dayjs vs luxon vs js-joda vs moment
JavaScriptにおける日付操作ライブラリの比較
date-fnsdayjsluxonjs-jodamoment類似パッケージ:

JavaScriptにおける日付操作ライブラリの比較

date-fnsdayjsjs-jodaluxonmoment はいずれも JavaScript で日付や時刻を扱うためのライブラリです。これらのライブラリは、日付のパース、フォーマット、計算、タイムゾーン変換などの共通の課題を解決しますが、アーキテクチャ、パフォーマンス特性、API設計、国際化対応において大きく異なります。特に、moment は公式に非推奨とされており、新規プロジェクトでの使用は推奨されません。他の4つはそれぞれ異なる設計哲学を持ち、プロジェクトの要件に応じて適切な選択が求められます。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
date-fns43,344,50436,47722.6 MB9131年前MIT
dayjs34,734,69448,560679 kB1,1984ヶ月前MIT
luxon20,396,35616,3624.59 MB1966ヶ月前MIT
js-joda47,8631,654-147年前BSD-3-Clause
moment048,0614.35 MB2902年前MIT

日付操作ライブラリ比較:date-fns、dayjs、js-joda、luxon、moment

フロントエンド開発で日付を扱う際、適切なライブラリ選びはパフォーマンス・メンテナンス性・開発体験に大きく影響します。この記事では、代表的な5つのJavaScript日付ライブラリ — date-fnsdayjsjs-jodaluxonmoment — を、実務の観点から徹底比較します。

⚠️ 重要な前提:moment.js は非推奨です

まず最初に明確にしておきます。moment は公式に非推奨(deprecated)とされていますnpmページおよびGitHubリポジトリには「プロジェクトはメンテナンスモードに入っており、新規プロジェクトでの使用は推奨されない」と記載されています。既存コードの保守には使えますが、新規プロジェクトでは絶対に選ばないでください。以下では比較の公平性のために言及しますが、選択肢としては除外すべきです。

🧩 アーキテクチャ設計:ミュータブル vs イミュータブル

日付ライブラリの根幹となる設計思想は、「オブジェクトを変更するか(ミュータブル)」それとも「新しいインスタンスを返すか(イミュータブル)」です。

momentミュータブル です。メソッド呼び出しで元のオブジェクトが変更されます。

// moment: ミュータブル(危険!)
const now = moment();
const tomorrow = now.add(1, 'day');
console.log(now.isSame(tomorrow)); // true ← now も変更されている!

一方、date-fnsdayjsjs-jodaluxon はすべて イミュータブル を採用しています。安全で予測可能な動作が得られます。

// date-fns: イミュータブル
import { addDays } from 'date-fns';
const now = new Date();
const tomorrow = addDays(now, 1);
console.log(now === tomorrow); // false ← 別のインスタンス

// dayjs: イミュータブル
import dayjs from 'dayjs';
const now = dayjs();
const tomorrow = now.add(1, 'day');
console.log(now.isSame(tomorrow)); // false

// js-joda: イミュータブル
import { LocalDate } from 'js-joda';
const today = LocalDate.now();
const tomorrow = today.plusDays(1);
console.log(today.equals(tomorrow)); // false

// luxon: イミュータブル
import { DateTime } from 'luxon';
const now = DateTime.now();
const tomorrow = now.plus({ days: 1 });
console.log(now.hasSame(tomorrow, 'day')); // false

💡 フロントエンド開発では、状態管理との整合性やバグ防止のため、イミュータブル設計が強く推奨されます。この点で moment は時代遅れです。

📦 モジュール設計:ツリーシェイキング対応

バンドルサイズを最適化するには、使った関数だけが含まれる「ツリーシェイキング」対応が必須です。

date-fns関数ベース の設計で、個別の関数を直接インポートできます。

// date-fns: 関数単位でインポート → 最小バンドル
import { format, parseISO, addDays } from 'date-fns';

dayjs軽量コア + プラグイン 方式です。基本機能は小さいですが、追加機能(例:相対時間、ロケール)はプラグインとして後から読み込みます。

// dayjs: コア + 必要なプラグインのみ
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);

js-jodaluxonクラスベース で、必要なクラスや静的メソッドをインポートします。ただし、内部的に依存が多い場合があり、完全なツリーシェイキングは難しいことがあります。

// js-joda: クラス単位でインポート
import { LocalDateTime, ZoneId } from 'js-joda';

// luxon: 名前付きインポート
import { DateTime, Duration } from 'luxon';

💡 SPAやモバイル向けアプリでは、date-fns または dayjs がバンドルサイズ面で有利です。

🌍 タイムゾーンと国際化(i18n)対応

グローバルアプリ開発では、タイムゾーンや多言語対応が必須です。

date-fnsタイムゾーン非対応 です。UTCやローカル時刻は扱えますが、任意のタイムゾーン(例:Asia/Tokyo)での計算はできません。i18nは別途 date-fns/locale からロケールをインポートします。

// date-fns: タイムゾーン非対応
import { format } from 'date-fns';
import { ja } from 'date-fns/locale';
format(new Date(), 'yyyy年MM月dd日', { locale: ja });

dayjsプラグインでタイムゾーン対応 します。timezone プラグインを使えば、任意のタイムゾーンで日付操作が可能です。

// dayjs: タイムゾーンプラグイン
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
dayjs.extend(timezone);

dayjs.tz('2023-01-01', 'America/New_York').tz('Asia/Tokyo').format();

js-jodaJavaのJSR-310仕様に準拠 しており、ネイティブで強力なタイムゾーンサポート を備えています。ZoneIdZonedDateTime といったクラスで正確な計算が可能です。

// js-joda: ネイティブタイムゾーン
import { ZonedDateTime, ZoneId } from 'js-joda';
const tokyoTime = ZonedDateTime.now(ZoneId.of('Asia/Tokyo'));

luxonネイティブでタイムゾーン対応 しており、ブラウザの Intl API を活用します。設定不要で高精度な変換が可能です。

// luxon: 組み込みタイムゾーン
import { DateTime } from 'luxon';
const tokyo = DateTime.now().setZone('Asia/Tokyo');

💡 タイムゾーンを多用するアプリ(例:スケジューラ、国際物流)では、js-jodaluxon が最適です。dayjs は軽量さを犠牲にせず対応したい場合に検討できます。

🧪 日付のパースとフォーマット

ユーザー入力やAPIレスポンスからの日付パース、表示用フォーマットも重要です。

date-fnsparseformat で柔軟に対応します。フォーマット文字列は独自仕様ですが直感的です。

// date-fns
import { parse, format } from 'date-fns';
const date = parse('2023-01-01', 'yyyy-MM-dd', new Date());
const str = format(date, 'yyyy年MM月dd日');

dayjsdayjs(string) でISO形式を自動パースし、.format() で出力します。カスタムフォーマットも可能。

// dayjs
const date = dayjs('2023-01-01');
const str = date.format('YYYY年MM月DD日');

js-jodaDateTimeFormatter を使って厳密にパース・フォーマットします。Java経験者には馴染みやすいです。

// js-joda
import { LocalDate, DateTimeFormatter } from 'js-joda';
const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd');
const date = LocalDate.parse('2023-01-01', formatter);
const str = date.format(formatter);

luxonDateTime.fromFormat().toFormat() を使います。フォーマット文字列はUnicode Technical Standard #35に準拠。

// luxon
import { DateTime } from 'luxon';
const date = DateTime.fromFormat('2023-01-01', 'yyyy-MM-dd');
const str = date.toFormat('yyyy年MM月dd日');

💡 シンプルなユースケースなら date-fnsdayjs で十分。厳密なフォーマット制御が必要なら js-jodaIntl連携重視なら luxon が向いています。

🔁 相互運用性と標準APIとの親和性

他のライブラリや標準APIとの連携も考慮しましょう。

  • date-fns: 純粋な Date オブジェクトを入出力するため、他ライブラリとの連携が容易。
  • dayjs: .toDate()Date に変換可能。軽量で多くのプロジェクトで採用されている。
  • js-joda: Javaの日付APIに似ているが、JavaScript標準とは異なる。Date との変換には注意が必要。
  • luxon: ブラウザの Intl API を内部で使い、Date との変換も簡単。現代的な設計。

📊 まとめ:各ライブラリの特徴と選定基準

ライブラリタイムゾーンバンドルサイズ学習コスト推奨用途
date-fns◎ (最小)軽量SPA、シンプルな日付操作
dayjs△ (プラグイン)汎用フロントエンド、軽量かつ拡張性が必要
js-joda複雑な日付計算、Java経験者
luxon国際化アプリ、モダンブラウザ向け
moment✘ (大きい)非推奨:新規プロジェクトで使用禁止

💡 最終的なアドバイス

  • 新規プロジェクトで moment を使うのは絶対にやめましょう。技術的負債になります。
  • 軽量さとシンプルさが最優先date-fnsdayjs を選ぶ。
  • タイムゾーンや国際化が必須luxon(モダンで直感的)か js-joda(計算精度重視)。
  • 既存コードが moment なら → 段階的に dayjs(APIが類似)へ移行するのが現実的です。

正しいライブラリを選ぶことで、日付周りのバグを減らし、アプリの信頼性と開発速度を両立できます。

選び方: date-fns vs dayjs vs luxon vs js-joda vs moment

  • date-fns:

    date-fns は関数ベースでツリーシェイキングに最適化されており、バンドルサイズを極限まで抑えたい軽量SPAやモバイル向けアプリに最適です。ただし、タイムゾーン操作には非対応なので、ローカル時刻やUTCのみで済むシンプルなユースケースに向いています。イミュータブル設計で安全に利用でき、Dateオブジェクトとの相互運用性も高いです。

  • dayjs:

    dayjs は軽量なコアにプラグイン機構を組み合わせた設計で、必要最小限の機能だけをバンドルできます。moment.js に似たチェーンメソッドAPIを持ちながらイミュータブルで、既存のmomentユーザーの移行先としても人気です。タイムゾーンや相対時間などの高度な機能はプラグインで追加可能ですが、複雑な日付計算には向かない場合があります。

  • luxon:

    luxon はモダンブラウザのIntl APIを活用した設計で、タイムゾーンやロケール対応が組み込みで強力です。イミュータブルで直感的なAPIを持ち、国際化対応が必要なグローバルアプリやモダンなフロントエンドプロジェクトに最適です。ただし、古いブラウザをサポートする必要がある場合はpolyfillが必要になる点に注意してください。

  • js-joda:

    js-joda はJavaのJSR-310仕様をJavaScriptに移植したもので、非常に正確で堅牢な日付計算が可能です。タイムゾーンや暦法に関する複雑な要件がある金融系システムや業務アプリ向けです。ただし、学習コストがやや高く、バンドルサイズも大きめなので、シンプルなWebアプリにはオーバースペックになることがあります。

  • moment:

    moment は公式に非推奨(deprecated)とされており、新規プロジェクトでの使用は絶対に避けてください。既存コードの保守目的でのみ使用すべきです。ミュータブル設計による予期しない副作用、大きなバンドルサイズ、モダンなJavaScriptのベストプラクティスに合わない点など、多くの問題があります。新規開発では必ず代替ライブラリを検討してください。

date-fns のREADME

🔥️ NEW: date-fns v4.0 with first-class time zone support is out!

date-fns

date-fns provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js

👉 Documentation

👉 Blog


It's like Lodash for dates

  • It has 200+ functions for all occasions.
  • Modular: Pick what you need. Works with webpack, Browserify, or Rollup and also supports tree-shaking.
  • Native dates: Uses existing native type. It doesn't extend core objects for safety's sake.
  • Immutable & Pure: Built using pure functions and always returns a new date instance.
  • TypeScript: The library is 100% TypeScript with brand-new handcrafted types.
  • I18n: Dozens of locales. Include only what you need.
  • and many more benefits
import { compareAsc, format } from "date-fns";

format(new Date(2014, 1, 11), "yyyy-MM-dd");
//=> '2014-02-11'

const dates = [
  new Date(1995, 6, 2),
  new Date(1987, 1, 11),
  new Date(1989, 6, 10),
];
dates.sort(compareAsc);
//=> [
//   Wed Feb 11 1987 00:00:00,
//   Mon Jul 10 1989 00:00:00,
//   Sun Jul 02 1995 00:00:00
// ]

The library is available as an npm package. To install the package run:

npm install date-fns --save

Docs

See date-fns.org for more details, API, and other docs.


License

MIT © Sasha Koss