date-fns、dayjs、luxon は、JavaScript 環境で日付や時刻を扱うための主要なライブラリです。これらは、ネイティブの Date オブジェクトが持つ複雑さや不整合を解消し、より安全で予測可能な操作を提供することを目的としています。date-fns は関数型アプローチを採用し、ツリーシェイキングに優れた設計になっています。dayjs は、Moment.js に似たチェーン形式の API を提供しつつ、軽量さを維持しています。luxon は、Moment.js の開発者によって作成され、イミュータブルなオブジェクトと強力なタイムゾーンサポートを特徴としています。
JavaScript で日付や時刻を扱うことは、しばしば開発者にとって頭痛の種となります。ネイティブの Date オブジェクトは、ゼロベースの月や、文字列パースの挙動など、直感的でない部分が多く存在します。date-fns、dayjs、luxon は、こうした問題を解決するために設計された代表的なライブラリです。これらはそれぞれ異なる哲学を持っており、プロジェクトの要件によって最適な選択が変わります。
ライブラリの使い勝手は、API の設計思想によって大きく異なります。コードの読みやすさや、チームの習熟度に影響する重要なポイントです。
date-fns は、関数型プログラミングの原則に基づいています。
// date-fns: 関数を呼び出して操作
import { addDays, format } from 'date-fns';
const date = new Date();
const nextWeek = addDays(date, 7);
console.log(format(nextWeek, 'yyyy-MM-dd'));
dayjs は、Moment.js に似たチェーン形式の API を採用しています。
// dayjs: メソッドチェーンで操作
import dayjs from 'dayjs';
const nextWeek = dayjs().add(7, 'day');
console.log(nextWeek.format('YYYY-MM-DD'));
luxon は、イミュータブルなオブジェクトをベースにしています。
DateTime オブジェクトが不変であり、操作ごとに新しいインスタンスを返します。// luxon: 不変オブジェクトで操作
import { DateTime } from 'luxon';
const nextWeek = DateTime.now().plus({ days: 7 });
console.log(nextWeek.toFormat('yyyy-MM-dd'));
グローバルなアプリケーションでは、タイムゾーンの扱いが不可欠です。ライブラリによって、このサポート体制に大きな差があります。
date-fns は、コアパッケージではタイムゾーンを直接扱えません。
date-fns-tz などのパッケージを組み合わせる必要があります。// date-fns: 追加パッケージが必要
import { zonedTimeToFormat } from 'date-fns-tz';
const date = new Date();
console.log(zonedTimeToFormat(date, 'America/New_York', 'yyyy-MM-dd'));
dayjs は、プラグインシステムを通じてタイムゾーンをサポートします。
timezone プラグインを明示的に読み込む必要があります。// dayjs: プラグインの読み込みが必要
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
console.log(dayjs().tz('America/New_York').format('YYYY-MM-DD'));
luxon は、タイムゾーン処理を標準でサポートしています。
// luxon: 標準機能で扱える
import { DateTime } from 'luxon';
const date = DateTime.now().setZone('America/New_York');
console.log(date.toFormat('yyyy-MM-dd'));
多言語対応が必要な場合、ロケールの設定方法が開発効率に影響します。
date-fns は、言語ごとにパッケージが分かれています。
// date-fns: ロケールを引数で指定
import { format } from 'date-fns';
import { ja } from 'date-fns/locale';
console.log(format(new Date(), 'yyyy 年 MM 月 dd 日', { locale: ja }));
dayjs は、グローバルまたはローカルにロケールを設定します。
dayjs.locale('ja') のように一度設定すれば、以降の操作に適用されます。// dayjs: グローバルにロケール設定
import dayjs from 'dayjs';
import 'dayjs/locale/ja';
dayjs.locale('ja');
console.log(dayjs().format('YYYY 年 MM 月 DD 日'));
luxon は、オブジェクト生成時にロケールを指定します。
// luxon: インスタンスごとにロケール指定
import { DateTime } from 'luxon';
const date = DateTime.now().setLocale('ja');
console.log(date.toFormat('yyyy 年 MM 月 dd 日'));
日付オブジェクトが書き換えられてしまうと、バグの原因になります。各ライブラリは、この問題にどうアプローチしているでしょうか。
date-fns は、ネイティブの Date オブジェクトを使いますが、関数は常に新しいインスタンスを返します。
Date オブジェクトを変更しないため、安全です。Date オブジェクト自体は変更可能なので注意が必要です。// date-fns: 元の値は変更されない
import { addDays } from 'date-fns';
const original = new Date();
const modified = addDays(original, 1);
// original は変更されていない
dayjs は、完全にイミュータブルな設計です。
Dayjs オブジェクトを返します。// dayjs: 完全にイミュータブル
import dayjs from 'dayjs';
const original = dayjs();
const modified = original.add(1, 'day');
// original は変更されていない
luxon も、完全にイミュータブルです。
DateTime オブジェクトは不変であり、操作ごとに新しいインスタンスが生成されます。// luxon: 完全にイミュータブル
import { DateTime } from 'luxon';
const original = DateTime.now();
const modified = original.plus({ days: 1 });
// original は変更されていない
| 特徴 | date-fns | dayjs | luxon |
|---|---|---|---|
| API スタイル | 🧩 関数型 | 🔗 チェーン形式 | 🧱 オブジェクト指向 |
| タイムゾーン | ⚠️ 追加パッケージ必要 | ⚠️ プラグイン必要 | ✅ 標準サポート |
| イミュータブル | ✅ 関数レベル | ✅ 完全サポート | ✅ 完全サポート |
| 国際化 | 📦 言語ごとインポート | 🌐 グローバル設定 | 🌏 インスタンス設定 |
| ネイティブ依存 | 📅 Date オブジェクト | 🔧 独自ラッパー | 🌍 Intl API 基盤 |
プロジェクトの要件に応じて、以下の基準で選定することをお勧めします。
date-fns は、モダンなバンドラー環境で、必要な機能だけを効率的に利用したい場合に最適です — 特に、関数型プログラミングの恩恵を受けたいチームに向いています。ただし、タイムゾーン処理が必要な場合は、追加の依存関係を管理するコストを考慮してください。
dayjs は、Moment.js からの移行や、直感的なチェーン操作を好む場合に適しています — 軽量でありながら、豊富なプラグインエコシステムを活用できます。シンプルさを保ちつつ、拡張性を求めているプロジェクトに良いでしょう。
luxon は、信頼性と機能性を最優先する場合に選ぶべきです — タイムゾーンや国際化を標準で扱えるため、複雑なグローバルアプリケーションに適しています。ネイティブの Intl API を活用しているため、長期的なメンテナンス性も高いです。
結論として:単純な日付表示なら date-fns または dayjs で十分ですが、タイムゾーンや複雑な計算が絡む場合は luxon が最も堅牢な選択肢となります。チームの熟悉度と、プロジェクトが求める機能の範囲を天秤にかけて決定してください。
date-fns を選ぶべきなのは、関数型プログラミングスタイルを好み、バンドルサイズを最小限に抑えるためにツリーシェイキングを重視する場合です。特定の機能だけをインポートできるため、プロジェクトに必要な部分だけを取り入れられます。ただし、タイムゾーン処理には追加のパッケージが必要な点に注意してください。
dayjs は、Moment.js から移行したいプロジェクトや、チェーン形式の API に慣れているチームに適しています。拡張性がプラグインベースで提供されるため、必要な機能だけを後から追加できます。軽量でありながら、直感的な操作性を維持したい場合に最適な選択肢です。
luxon は、タイムゾーン処理や国際化(i18n)をネイティブレベルでサポートしてほしい場合に最適です。イミュータブルなオブジェクト設計により、予期しない状態変更を防げます。複雑な日付計算や、信頼性の高い時刻管理が必要な大規模アプリケーションに向いています。
🔥️ 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.