moment、dayjs、luxon、js-joda は、JavaScript 環境で日時の解析、操作、フォーマットを行うための主要なライブラリです。moment は長年デファクトスタンダードでしたが、現在は保守モードに入っており、新規プロジェクトでの使用は推奨されません。dayjs は moment と互換性のある API を持ちつつ軽量で、luxon は moment の開発者によって作られた不変型ライブラリでネイティブの Intl API を利用します。js-joda は Java の日時 API のポートであり、厳格な不変性を求めるドメインロジックに適しています。
JavaScript で日時を扱うことは、一見簡単そうで実は複雑な課題です。タイムゾーン、うるう年、ローカライゼーションなど、考慮すべき点が多くあります。moment、dayjs、luxon、js-joda は、この問題を解決するための主要な選択肢ですが、それぞれ設計思想とトレードオフが異なります。エンジニアリングの観点から、これらのライブラリを深く比較します。
ライブラリを選定する際、まず確認すべきはメンテナンス状況です。長期にわたるプロジェクトでは、ライブラリが将来もサポートされ続けるかが重要です。
moment は現在、保守モードに入っています。
// moment: 保守モード入り
// 新規プロジェクトでは避けるべき
const m = moment();
dayjs はアクティブに開発が続いています。
// dayjs: アクティブ開発中
import dayjs from 'dayjs';
const d = dayjs();
luxon も安定したメンテナンスが続いています。
moment の開発者によって作成されました。// luxon: 安定メンテナンス
import { DateTime } from 'luxon';
const d = DateTime.now();
js-joda は堅牢性を重視して開発されています。
// js-joda: 堅牢性重視
import { LocalDateTime } from '@js-joda/core';
const d = LocalDateTime.now();
日時オブジェクトが操作後に自身を書き換えるか(可変)、新しいオブジェクトを返すか(不変)は、バグの発生率に直結します。
moment は可変型です。
// moment: 可変型
const a = moment();
const b = a; // 参照コピー
a.add(1, 'day');
console.log(b.format()); // a と b が同じ日時になる
dayjs も基本的に可変型です。
moment との互換性を重視した設計です。// dayjs: 可変型(デフォルト)
const a = dayjs();
const b = a; // 参照コピー
const c = a.add(1, 'day'); // 新しいインスタンスを返す場合もあるが注意が必要
luxon は不変型です。
// luxon: 不変型
const a = DateTime.now();
const b = a; // 参照コピーだが中身は変わらない
const c = a.plus({ days: 1 }); // a は変更されない
console.log(a.equals(c)); // false
js-joda は厳格な不変型です。
// js-joda: 厳格な不変型
const a = LocalDateTime.now();
const b = a;
const c = a.plusDays(1); // a は変更されない
実際のコードで、どのように日時を扱うか比較します。 parsing(解析)、manipulation(操作)、formatting(フォーマット)の 3 点を見ます。
moment は文字列を柔軟に解析します。
// moment
const m = moment('2023-10-01');
dayjs も柔軟な解析を行います。
moment とほぼ同じ挙動です。// dayjs
const d = dayjs('2023-10-01');
luxon は形式を明確に指定します。
// luxon
const l = DateTime.fromISO('2023-10-01');
js-joda は厳密な形式を要求します。
// js-joda
const j = LocalDateTime.parse('2023-10-01T00:00');
moment はチェーン操作で加算します。
// moment
const m = moment().add(1, 'day').subtract(2, 'hour');
dayjs もチェーン操作をサポートします。
moment と同じ文法で書けます。// dayjs
const d = dayjs().add(1, 'day').subtract(2, 'hour');
luxon はオブジェクトで単位を指定します。
// luxon
const l = DateTime.now().plus({ days: 1 }).minus({ hours: 2 });
js-joda はメソッド名で単位を区別します。
// js-joda
const j = LocalDateTime.now().plusDays(1).minusHours(2);
moment はトークン形式を使います。
YYYY-MM-DD などの形式は一般的です。// moment
const str = moment().format('YYYY-MM-DD');
dayjs もトークン形式を使います。
moment と互換性があります。// dayjs
const str = dayjs().format('YYYY-MM-DD');
luxon は Unicode 標準の形式を使います。
yyyy-MM-dd など、小文字区別があります。// luxon
const str = DateTime.now().toFormat('yyyy-MM-dd');
js-joda はフォーマッタオブジェクトを使います。
// js-joda
const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd');
const str = LocalDateTime.now().format(formatter);
グローバルなアプリでは、タイムゾーン処理が不可欠です。ここがライブラリ間の大きな違いになります。
moment はプラグインが必要です。
moment-timezone を別途インストールします。// moment
import 'moment-timezone';
moment.tz('2023-10-01', 'America/New_York');
dayjs もプラグインが必要です。
timezone プラグインを読み込みます。// dayjs
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz('2023-10-01', 'America/New_York');
luxon は標準機能でサポートします。
Intl API を内部で利用します。// luxon
DateTime.fromISO('2023-10-01', { zone: 'America/New_York' });
js-joda は別途パッケージが必要です。
@js-joda/timezone を使用します。// js-joda
import { ZonedDateTime, ZoneId } from '@js-joda/core';
import '@js-joda/timezone';
ZonedDateTime.parse('2023-10-01T00:00-04:00[America/New_York]');
ブラウザのサポート範囲も選定基準になります。
moment は依存関係がありません。
dayjs も依存関係がありません。
luxon は Intl API に依存します。
js-joda は依存関係が少ないです。
| 特徴 | moment | dayjs | luxon | js-joda |
|---|---|---|---|---|
| 保守状況 | 🛑 保守モード | ✅ アクティブ | ✅ 安定 | ✅ 安定 |
| 変更性質 | 🔴 可変 | 🔴 可変 | 🟢 不変 | 🟢 不変 |
| サイズ感 | 🐘 大きい | 🐦 軽量 | 🐕 中程度 | 🐕 中程度 |
| タイムゾーン | 🔌 プラグイン | 🔌 プラグイン | ✅ 標準機能 | 🔌 別パッケージ |
| API 风格 | チェーン | チェーン | オブジェクト | メソッド名 |
| 推奨度 | ❌ 非推奨 | ✅ 高い | ✅ 高い | ⚠️ 特殊用途 |
moment は、もはや新規プロジェクトの選択肢ではありません。保守モード入りしているため、技術的負債になります。既存プロジェクトであれば、移行計画を立てるべきです。
dayjs は、moment のような書き心地を維持しつつ、軽量さを求めている場合に最適です。フロントエンドの UI 表示や、シンプルな日時操作に向いています。プラグイン構成により、必要な機能だけを含められるのも魅力です。
luxon は、不変型による安全性と、標準仕様への準拠を重視する場合に選べきです。状態管理の複雑さを減らしたい大規模アプリや、タイムゾーン処理を標準機能で済ませたい場合に有利です。ただし、古いブラウザサポートには注意が必要です。
js-joda は、日時計算の正確性がビジネスロジックの核心となる場合に適しています。金融システムやスケジューリングシステムなど、バグが許されない領域での利用が考えられます。フロントエンドの UI 処理としてはオーバーワークになる可能性があります。
最終的なアドバイス:新規プロジェクトでは dayjs または luxon を選定し、moment は避けてください。不変性を求めるなら luxon、軽量さと互換性を求めるなら dayjs が良いでしょう。
dayjs は、moment のような直感的な API を求めつつ、バンドルサイズを小さく抑えたい場合に最適です。プラグイン機構により必要な機能だけを追加できるため、軽量さを維持しながら拡張できます。既存の moment プロジェクトからの移行コストが最も低いのも特徴です。ただし、デフォルトでは可変型であるため、副作用に注意する必要があります。
js-joda は、厳格な不変性と型安全性が求められるビジネスロジックやバックエンド寄りの処理に適しています。Java の ThreeTen プロジェクトに基づいており、日時計算の信頼性が非常に高いです。ただし、API が他のライブラリとは大きく異なり、学習コストが高いため、フロントエンドの UI 処理よりもドメイン層での利用を検討すべきです。
luxon は、不変型 API を採用しており、予期せぬ状態変化を防ぎたいアーキテクチャに適しています。ネイティブの Intl API を利用するため、最新ブラウザでは軽量に動作しますが、古いブラウザではポリフィルが必要です。moment の開発者による後継ライブラリであり、バランスの取れた選択と言えます。
moment は、すでに保守モードに入っているため、新規プロジェクトでの使用は避けるべきです。既存のレガシープロジェクトを維持する場合や、膨大な既存コードベースを抱えており移行が現実的に困難な場合にのみ検討します。将来的なメンテナンスコストを考慮すると、代替ライブラリへの移行を計画すべきです。
English | 简体中文 | 日本語 | Português Brasileiro | 한국어 | Español (España) | Русский | Türkçe | සිංහල | עברית
Fast 2kB alternative to Moment.js with the same modern API
Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates and times for modern browsers with a largely Moment.js-compatible API. If you use Moment.js, you already know how to use Day.js.
dayjs().startOf('month').add(1, 'day').set('year', 2018).format('YYYY-MM-DD HH:mm:ss');
You can find more details, API, and other docs on day.js.org website.
npm install dayjs --save
It's easy to use Day.js APIs to parse, validate, manipulate, and display dates and times.
dayjs('2018-08-08') // parse
dayjs().format('{YYYY} MM-DDTHH:mm:ss SSS [Z] A') // display
dayjs().set('month', 3).month() // get & set
dayjs().add(1, 'year') // manipulate
dayjs().isBefore(dayjs()) // query
Day.js has great support for internationalization.
But none of them will be included in your build unless you use them.
import 'dayjs/locale/es' // load on demand
dayjs.locale('es') // use Spanish locale globally
dayjs('2018-05-05').locale('zh-cn').format() // use Chinese Simplified locale in a specific instance
A plugin is an independent module that can be added to Day.js to extend functionality or add new features.
import advancedFormat from 'dayjs/plugin/advancedFormat' // load on demand
dayjs.extend(advancedFormat) // use plugin
dayjs().format('Q Do k kk X x') // more available formats

Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
[Become a sponsor via Github] [Become a sponsor via OpenCollective]
This project exists thanks to all the people who contribute.
Please give us a 💖 star 💖 to support us. Thank you.
And thank you to all our backers! 🙏
Day.js is licensed under a MIT License.