Moment.js と date-fns でローカライズされた日付文字列への変換方法を調査してみた

Moment.js と date-fns でローカライズされた日付文字列への変換方法を調査してみた

こんにちは。最近、 PHP Conference Japan 2023 のトーク募集に申し込んだ k-so16 です。初めて proposal を提出したので、採択されるかなという不安と、採択されたらいいなという期待の半々の気持ちで日々過ごしています (笑)

とあるプロジェクトで、日付の操作に Moment.js を利用し、日本語の日付文字列を出力するために date-fns を利用しているコードを見かけました。わざわざ date-fns を使っているのは、 Moment.js だけでは日本語の日付文字列に変換できないのだろうかと疑問に思いました。

それぞれのライブラリーを調べてみると、どちらも日本語の日付文字列に変換できることがわかりました。残念ながら、なぜ使い分けているかはわかりませんでした。

本記事では、 Moment.js と date-fns でローカライズされた日付文字列に変換する方法 を紹介します。

本記事で想定する読者層は以下の通りです。

  • Moment.js についての基礎的な使い方を知っている
  • date-fns についての基礎的な使い方を知っている

Moment.js と date-fns の違い

Moment.js と date-fns は、どちらも 日付や時間を扱うライブラリー です。日付の加算や 2 つの日付の比較など、さまざまな演算を簡単に記述できます。

2 つのライブラリーできることは大きく変わりません。大きな違いとして、返される日付オブジェクトが違うということが挙げられます。

  • Moment.js は基本的に Moment オブジェクトを返す
  • date-fns は基本的に Date オブジェクトを返す

Moment.js は独自の Moment オブジェクトを返します。一方、 date-fns は標準の Date オブジェクトを返します。

Moment.js は Moment オブジェクトを基本的に返すため、複数の日付の操作を、 メソッドチェイン で書くことができます。ただし、 Date を受け取るインタフェースに Moment.js で操作した日付データを渡す際には、その都度 .toDate() で型変換する必要があります。

一方、 date-fns の場合は Date オブジェクトを返すため、 Moment.js のように複数の操作をメソッドチェインで書くことはできません。かわりに、 date-fns で操作した日付データは、 Date を受け取るインタフェースへ 型変換をすることなく 、直接渡すことができます。

ローカライズされた日付文字列への変換方法

Moment.js と date-fns では、ローカライズの方法や、日付文字列への変換フォーマットの違いはあれど、基本的に同じ日付文字列を出力できます。

以下のセクションでは、ロケールを日本に設定して、 2023年7月25日 (火) のような、年月日と日本語の曜日を含む日付文字列に変換する場合を考えてみます。

なお、コード例は Node.js 上での動作を想定し、 CommonJS の記法で記述しています。 ECMAScript の記法の場合も、 require の行を import に変える ことで、同様の動作になるはずです。

Moment.js の場合

Moment.js の場合、 locale() というメソッドを利用することで、扱う日付のロケールを設定できます。 ロケールを設定したあと、 format() で日付のフォーマット文字列を生成する と、ローカライズされた日付文字列に変換できます。

Moment.js では、日本語にローカライズした状態でフォーマット文字列に LL を指定すると、 2023年7月25日 のように、年月日の日付文字列に変換します。また、 ddd を指定すると、 のように、短い曜日表記に変換されます。

Moment.js でローカライズされた日付文字列に変換するコード例は以下の通りです。

Moment.js でローカライズされた日付文字列に変換するコード例
const moment = require('moment');

const date = moment().locale('ja').format('LL (ddd)');
console.log(date); // 出力例: 2023年7月25日 (火)

date-fns の場合

date-fns の場合は、 date-fns/locale から、 対象のロケールのオブジェクトを読み込みます。 日付文字列をローカライズするには、 date-fns の format() メソッドの第 3 引数に、 locale プロパティをもつオブジェクト を指定します。

date-fns では、日本語にローカライズした状態でフォーマット文字列に PPP を指定すると、 2023年7月25日 のように、年月日の日付文字列に変換します。また、 E を指定すると、 のように、短い曜日表記に変換されます。

date-fns でローカライズされた日付文字列に変換するコード例は以下の通りです。

date-fns でローカライズされた日付文字列に変換するコード例
const { format } = require('date-fns');
const { ja } = require('date-fns/locale');

const date = format(new Date(), 'PPP (E)', { locale: ja });
console.log(date); // 出力例: 2023年7月25日 (火)

Moment.js と date-fns のフォーマットの比較

日付文字列へ変換する際に、 Moment.js と date-fns でフォーマットの指定方法を比較してみます。年月日と曜日、および時分秒のそれぞれについて、よく使われそうなフォーマットを比較してみます。

以下の表は Moment.js と date-fns の日付フォーマットの一部です。

項目 Moment.js のフォーマット date-fns のフォーマット デフォルトの表示例 日本語の表示例
YYYY yyyy 2023 2023
M M 7 7
月 (2 桁表記) MM MM 07 07
月 (ローカライズ表記 (省略形)) MMM MMM Jul 7月
月 (ローカライズ表記) MMMM MMMM July 7月
D d 1 1
日 (2 桁表記) DD dd 01 01
日 (ローカライズ表記) Do do 1st 1日
曜日 (ローカライズ表記 (省略形)) ddd EEE Sat
曜日 (ローカライズ表記) dddd EEEE Saturday 土曜日
時間 (12 時間表記) h h 1 1
時間 (12 時間表記 (2 桁)) hh hh 01 01
時間 (24 時間表記) H H 13 13
時間 (24 時間表記 (2 桁)) HH HH 13 13
分 (2 桁表記) mm mm 01 01
秒 (2 桁表記) ss ss 02 02
年月日 L P 07/01/2023 2023/07/01
年月日 (ローカライズ表記 (省略形)) ll PP Jul 1, 2023 ※1
年月日 (ローカライズ表記) LL PPP ※2 2023年7月1日
時分 LT p 12:01 PM 12:01
時分秒 LTS pp 12:01:25 PM 12:01:25

基本的に同じ表記に変換できますが、 残念ながら フォーマットは共通ではありません。 時間や分、秒のように、同じフォーマットのものもありますが、 ほとんどの場合はフォーマットが異なります。

また、上記の表の※1, ※2 は、 Moment.js と date-fns で変換結果が若干異なります。以下の表に、それぞれの変換結果の例を示します。

項目 Moment.js での表示例 date-fns での表示例
※1 2023年7月1日 2023/07/01
※2 July 1, 2023 July 1st, 2023

※1 では、Moment.js の場合、日本語にローカライズした年月日へ変換する場合は LLll も同じ結果になります。一方で、 date-fns の場合は PPPPP で結果が異なります。

また、※2 では、 date-fns の場合は日付の後ろに st のような接尾辞がつきますが、 Moment.js の場合はつきません。

混乱を避けるためにも、よほどの事情がない限りは Moment.js か date-fns の どちらか一方のみを利用 したほうが良さそうですね。

ちなみに、 Moment.js は公式ドキュメントで、新たな機能追加などの大きな変更は行わず、保守のみサポートすると述べています。そのため、新しくプロジェクトを立ち上げる際には、 date-fns や Luxon などの ほかのライブラリーを利用することを推奨 しています。

本記事を執筆する上で、以下の記事を参考にしました。

まとめ

本記事のまとめは以下の通りです。

  • Moment.js と date-fns でローカライズされた日付文字列に変換する方法を紹介
  • Moment.js と date-fns の代表的な変換フォーマットを紹介

以上、 k-so16 でした。ぜひ、それぞれのライブラリーでどのようなフォーマットに変換できるか試してみてくださいね (笑)

k-so16