Moment.jsのサポート終了に伴って、Day.jsへ移行する際に注意したいことまとめです。
基本的には機械的な移行が可能
公式でも迅速な移行をする場合に推奨されている通り、dayjsはmomentjsとの互換性が非常に高いため、単純に moment
-> dayjs
の一括置換でも大体問題ありません。
import moment from 'moment';
moment().format('YYYY-MM-DD'); // 2020-10-08
// ↓
import dayjs from 'dayjs';
dayjs().format('YYYY-MM-DD'); // 2020-10-08
localeの設定
localeを設定する場合には、先に対応するlocaleのimportが必要になります。
import 'dayjs/locale/ja';
dayjs.locale('ja');
timezoneの設定
こちらも先にimportが必要です。
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone'; // needs utc plugin
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault('Asia/Tokyo');
パースの挙動に陰りあり
こちら少しdayjsの挙動にハマってしまいました。
端的に言えば、生のdayjsでは文字列をコンストラクタの引数に渡した時に限りなく甘く解釈されてしまいます。
挙動を見てみましょう。
通常
const date = '2020-01-01';
console.log(new Date(date));
console.log(dayjs(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
console.log(moment(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
// Wed Jan 01 2020 09:00:00 GMT+0900 (日本標準時)
// 2020-01-01T00:00:00+09:00
// 2020-01-01T00:00:00+09:00
当然ですね。
nullを渡してみる
const date = null;
console.log(new Date(date));
console.log(dayjs(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
console.log(moment(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
// Thu Jan 01 1970 09:00:00 GMT+0900 (日本標準時)
// Invalid Date
// Invalid date
JavaScriptのDateオブジェクトにnullを渡す際の謎挙動は、JavaScriptのDateオブジェクトの罠として一定の認知があると思います。
https://qiita.com/digitter/items/02666885a229c29707d4
ただしこれはmomentjs, dayjsともにparseする際にinvalidになるようにしているため、気にしなくてよし。
(dayjsではこのissueとかで解決されている)
ちなみに 0を渡すと、
// Thu Jan 01 1970 09:00:00 GMT+0900 (日本標準時)
// 1970-01-01T09:00:00+09:00
// 1970-01-01T09:00:00+09:00
'2020-hoge-fuga'とか渡してみる
const date = "2020-hoge-fuga";
console.log(new Date(date));
console.log(dayjs(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
console.log(moment(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
// Invalid Date
// Invalid date
// Invalid Date (error!)
うんうん、そうですよね。
'2020-01-hoge'とか渡してみる
const date = "2020-01-fuga";
console.log(new Date(date));
console.log(dayjs(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
console.log(moment(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
// Invalid Date
// 2020-01-01T00:00:00+09:00
// Invalid Date (error!)
// 2020-01-01T00:00:00+09:00
............!!!!!
なんということでしょう、2020-01-01にパースされてしまいました。
dayjs単体の挙動だとこうなってしまうらしいので、dayjsのCustomParseFormatプラグインを使うと良いらしい。
import customParseFormat from "dayjs/plugin/customParseFormat";
dayjs.extend(customParseFormat);
const date = "2020-01-fuga";
console.log(new Date(date));
console.log(dayjs(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
console.log(moment(date, "YYYY-MM-DD hh:mm:ss Z", true).format());
// Invalid Date
// Invalid Date (error!)
// Invalid Date (error!)
instanceof チェック
if (v.constructor.name !== 'Moment') {
v = moment(v);
}
moment.jsでこんな感じの型チェックをしている場合は、以下に置き換え可能です。
if (!dayjs.isDayjs(v)) {
v = dayjs(v);
}
// or
if (!(dayjs() instanceof dayjs)) {
v = dayjs(v);
}
Moment.js依存のライブラリ
react-datetimeなど、momentjsに依存しているパッケージを導入している際には注意が必要です。
react-datetimeの例だとprops
のvalue
にmoment objectを渡していた箇所があったのですが、そこにdayjs objectを渡してしまっていました。ただこれでもエラーは発生しないものの(なんだって!)、出力結果が正しくありません(出力結果がすべて今日の日付になる)。
この例ではdayjs objectではなく dayjs().format()
などで日付形式の文字列を渡すことで正しく挙動します。
他にもmomentに依存するライブラリに、機械的に置換したためにdayjs objを渡してしまったままの箇所がないか、よくご確認ください。
ありがとう。サラバmoment.js。