JavaScript の日付処理は luxon が便利


はじめに

JavaScript で日付処理といえば moment.js が有名かと思います。
そんな中、私の関わるプロジェクトでは使用するライブラリを、 moment.js -> date-fns -> luxon と変更してきました。
そして今現在は luxon を使っています。

luxon は使っていて便利だな、と感じるライブラリです。
ここでは、これまで使用した処理の中で、私が便利だと思った機能をいくつか紹介します。
(基本的なものは割愛します。下記の参考リンクにもまとめられています。)

実際に使っている処理

DateTime 型を作成

これは基本的なものですが、これがないと始まらないので記載しておきました。

import { DateTime } from 'luxon';

// ISO format
DateTime.fromISO('2019-12-23T12:00:00.000000');
// JavaScript Date format
DateTime.fromJSDate(new Date());
// SQL format
DateTime.fromSQL('2017-05-15 09:12:34');

表示用に出力

toLocalString が個人的に好きです。
ローカライズにも対応しているのがありがたい。

const dateTime = DateTime.fromISO( ... );

// ISO 形式で出力
dateTime.toISO();
// 指定したフォーマット形式で出力
dateTime.toFormat('h:mma, dd-MM-yyyy');
// 定められたフォーマットで出力(ローカライズ対応)
dateTime.toLocaleString({ ...DateTime.DATE_MED });
/*
 * DATETIME_FULL
 * DATETIME_FULL_WITH_SECONDS
 * DATETIME_HUGE
 * DATETIME_HUGE_WITH_SECONDS
 * DATETIME_MED
 * DATETIME_MED_WITH_SECONDS
 * DATETIME_SHORT
 * DATETIME_SHORT_WITH_SECONDS
 * DATE_FULL
 * DATE_HUGE
 * DATE_MED
 * DATE_SHORT
 * TIME_24_SIMPLE
 * TIME_24_WITH_LONG_OFFSET
 * TIME_24_WITH_SECONDS
 * TIME_24_WITH_SHORT_OFFSET
 * TIME_SIMPLE
 * TIME_WITH_LONG_OFFSET
 * TIME_WITH_SECONDS
 * TIME_WITH_SHORT_OFFSET
 */

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
dateTime.toLocaleString({ year: 'numeric', month: 'short', day: 'numeric' }),

○○分以内に発生したイベントの判断

現在時刻との比較はよく使うので diffNow は便利ですね。

if (DateTime.fromISO(...).diffNow('minutes').minutes >= -3) { ... }
if (DateTime.fromISO(...).diff(..., 'minutes').minutes >= 60) { ... }

// DateTime.fromISO(...).diffNow().minutes とした場合、返り値が 0 になりました。
// これは DateTime オブジェクトは millisecond がデフォルトのためです。
// 単位を分にする場合は diffNow('minutes') と記載する必要があります。

祝日の判断

営業日判断などで利用します。

holidays.find((holiday) => {
  return holiday.hasSame(DateTime.local(), 'day');
} !== undefined

○○年後の開始月/日を取得

startOfendOf は非常に便利だと思います。
応用すれば、今月の初日や、現在時刻から00分や00秒の取得、といったこともできます。

// 15年後の同月一日を取得(現在が2019年12月なら2034/12/1)
DateTime.utc().plus({ years: 15 }).startOf('month');
// 15年後の開始日を取得(現在が2019年12月なら2034/1/1)
DateTime.utc().plus({ years: 15 }).startOf('year');

ハマったところ

diff/diffNow

フォーマットを指定しないと、milliseconds 以外の値が返ってこない、という状況で最初ハマりました。
差分を取得しているつもりなのに、if文が正しく動いてくれません。
分で評価したい場合は、diffNow('minutes').minutes とする必要があります。

ユニットテスト

我々のプロジェクトでは、サーバサイドでも日付時刻計算に luxon を使っています。
ローカルでテストコードを実行してユニットテスト成功していたものが、CI/CD環境ではエラーとなるケースに直面しました。
どの環境でも同じように動くように実装する必要性を強く感じました。

参考

逆引きLuxon集 〜moment.jsから乗り換えるために〜