date-fns、datejs、dayjs、luxon、moment はすべて JavaScript で日付と時刻を扱うためのライブラリです。これらは日付のパース、フォーマット、操作、国際化などの共通機能を提供しますが、設計思想、API スタイル、モジュール性、タイムゾーン対応、メンテナンス状況において大きく異なります。特に moment と datejs は公式に非推奨とされており、新規プロジェクトでの使用は避けるべきです。一方、date-fns、dayjs、luxon は現代的なフロントエンド開発に適した選択肢として活用されています。
フロントエンド開発で日付を扱うのは一見簡単ですが、タイムゾーン、ロケール、パフォーマンス、メンテナンス性など、実際には多くの課題があります。ここでは、代表的な5つの日付ライブラリを技術的に比較し、どの場面でどれを選ぶべきかを明らかにします。
まず重要な前提として、datejs と moment は 公式に非推奨 とされています。
datejs: npm ページ および GitHub で「このプロジェクトはメンテナンスされていません」と明記されています。最後のリリースは2007年であり、新規プロジェクトでの使用は避けてください。moment: 公式サイト および npm ページ で「プロジェクトはレガシー状態」とされ、「新しいプロジェクトでは他のライブラリを検討してください」と記載されています。以下では、これらの非推奨ライブラリも含めて技術的比較を行いますが、新規採用は推奨されません。
date-fns関数型スタイルで、各操作が独立した関数です。不変性が保たれます。
import { format, addDays } from 'date-fns';
import { ja } from 'date-fns/locale';
const now = new Date();
const tomorrow = addDays(now, 1);
const formatted = format(tomorrow, 'yyyy年MM月dd日 EEEE', { locale: ja });
// 例: "2024年06月15日 土曜日"
datejs(非推奨)ミュータブルな拡張メソッドを Date オブジェクトに追加します。
// datejs は Date.prototype を拡張する
Date.today().add({ days: 1 }).toString('yyyy年MM月dd日');
dayjsチェーン可能な API で、moment に似ていますが軽量です。
import dayjs from 'dayjs';
import 'dayjs/locale/ja';
import localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(localizedFormat);
dayjs.locale('ja');
const formatted = dayjs().add(1, 'day').format('YYYY年MM月DD日 dddd');
// 例: "2024年06月15日 土曜日"
luxonDateTime オブジェクトを使用し、Intl API に依存します。
import { DateTime } from 'luxon';
const formatted = DateTime.now()
.plus({ days: 1 })
.setLocale('ja')
.toFormat('yyyy年MM月dd日 cccc');
// 例: "2024年06月15日 土曜日"
moment(非推奨)チェーン可能ですが、内部でミュータブルな操作を行うことがあります。
import moment from 'moment';
import 'moment/locale/ja';
moment.locale('ja');
const formatted = moment().add(1, 'days').format('YYYY年MM月DD日 dddd');
タイムゾーン処理は多くのアプリケーションで重要です。各ライブラリの対応状況は大きく異なります。
date-fnsコアにはタイムゾーン機能が含まれていません。date-fns-tz という別パッケージが必要です。
import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz';
const utcDate = zonedTimeToUtc('2024-06-15 12:00:00', 'Asia/Tokyo');
const tokyoTime = utcToZonedTime(utcDate, 'Asia/Tokyo');
const formatted = format(tokyoTime, 'yyyy-MM-dd HH:mm:ss XXX', { timeZone: 'Asia/Tokyo' });
datejs(非推奨)タイムゾーンサポートは限定的で、信頼性に欠けます。
// datejs はタイムゾーンを正しく扱えません
Date.parse('2024-06-15T12:00:00+09:00'); // 危険
dayjstimezone プラグインを有効にする必要があります。
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
dayjs.extend(timezone);
const tokyoTime = dayjs().tz('Asia/Tokyo').format();
luxonネイティブで強力なタイムゾーンサポート。Intl API を直接利用するため、ブラウザのタイムゾーンデータに依存します。
import { DateTime } from 'luxon';
const tokyoTime = DateTime.now().setZone('Asia/Tokyo').toISO();
// 例: "2024-06-15T12:00:00.000+09:00"
moment(非推奨)moment-timezone という別パッケージが必要で、バンドルサイズが膨大になります。
import moment from 'moment-timezone';
const tokyoTime = moment().tz('Asia/Tokyo').format();
date-fns各関数が独立しているため、未使用のコードはビルド時に完全に削除されます(ツリーシェイキング)。最小限の機能しか使わない場合、非常に軽量になります。
dayjsコアは極小(約2KB)で、必要な機能だけをプラグインとして追加できます。ツリーシェイキングにも対応しています。
luxon単一のモジュールですが、ESM 対応により未使用のエクスポートは削除可能です。ただし、Intl API への依存があるため、機能自体はブラウザに委ねられます。
moment / datejs全体をインポートする必要があり、ツリーシェイキングが効きません。特に moment はロケールデータを含めると数十KBになります。
date-fns: 完全に不変。元の Date オブジェクトは変更されません。dayjs: 不変。新しいインスタンスを返します。luxon: 不変。新しい DateTime インスタンスを返します。moment: 表面上は不変に見えますが、内部でミュータブルな操作を行うことがあり、予期しない副作用を引き起こす可能性があります。datejs: Date オブジェクトを直接拡張・変更するため、完全にミュータブルです。これは大規模アプリではバグの温床になります。date-fns各ロケールが個別のファイルとして提供され、必要に応じてインポートします。
import { format } from 'date-fns';
import { ja } from 'date-fns/locale';
format(date, 'PPPP', { locale: ja });
dayjsロケールはプラグインとして提供され、動的ロードも可能です。
import 'dayjs/locale/ja';
dayjs.locale('ja');
luxonブラウザの Intl API に依存するため、OS やブラウザがサポートするロケールがそのまま利用できます。追加のロケールファイル不要。
DateTime.now().setLocale('ja-JP').toFormat('D');
moment / datejsロケールデータを手動でインポートする必要があり、バンドルサイズに悪影響を与えます。
| 要件 | 推奨ライブラリ |
|---|---|
| 最小限のバンドルサイズ、関数型スタイル、不変性重視 | date-fns |
moment に似た使いやすさ、軽量さ、プラグイン拡張性 | dayjs |
| 正確なタイムゾーン処理、ネイティブな国際化対応 | luxon |
| 新規プロジェクト | datejs と moment は使用禁止 |
date-fns、dayjs、luxon のいずれかを選んでください。dayjs がバランスが良いです。luxon が最も堅牢です。date-fns が最適です。これらの選択は、あなたのアプリケーションの規模、ユーザーの地理的分布、パフォーマンス要件、そしてチームの開発哲学によって決まるべきです。
date-fns は関数型アプローチを採用し、各機能が独立した関数として提供されるため、ツリーシェイキングとの相性が非常に良いです。不変性を保ち、軽量なバンドルを目指すモダンなビルド環境(例:Vite、Webpack)で最適です。ただし、タイムゾーン処理には追加の設定や Intl API への依存が必要です。
dayjs は moment に似たチェーン可能な API を持ちながら、極めて軽量で高速です。プラグインによる拡張性も高く、基本機能に加えてタイムゾーンやカスタムパースなどを必要に応じて追加できます。シンプルな日付操作が中心で、バンドルサイズを厳しく制限したいプロジェクトに最適です。
moment はかつて事実上の標準でしたが、公式ドキュメントおよび npm ページで「レガシー」として非推奨とされています。巨大なバンドルサイズ、ミュータブルな API、モダンな JavaScript のベストプラクティスに合わない設計が理由です。新規プロジェクトでは使用せず、既存コードの維持または段階的な移行のみを想定してください。
luxon は Intl API を基盤に構築されており、ネイティブなタイムゾーンやロケール対応が強力です。オブジェクト指向でチェーン可能な API を提供し、複雑な国際化要件や正確なタイムゾーン計算が必要なアプリケーションに向いています。ただし、古いブラウザではポリフィルが必要になる場合があります。
datejs は長年メンテナンスされておらず、npm ページおよび GitHub リポジトリで公式に非推奨(deprecated)と明記されています。新規プロジェクトでは絶対に使用しないでください。既存システムで使われている場合は、date-fns や dayjs への移行を検討すべきです。
🔥️ NEW: date-fns v4.0 with first-class time zone support is out!
date-fns provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js
👉 Blog
It's like Lodash for dates
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
See date-fns.org for more details, API, and other docs.