1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Moment.jsはDay.jsの夢を見るか?

Last updated at Posted at 2020-10-11

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の例だとpropsvalueにmoment objectを渡していた箇所があったのですが、そこにdayjs objectを渡してしまっていました。ただこれでもエラーは発生しないものの(なんだって!)、出力結果が正しくありません(出力結果がすべて今日の日付になる)。
この例ではdayjs objectではなく dayjs().format()などで日付形式の文字列を渡すことで正しく挙動します。

他にもmomentに依存するライブラリに、機械的に置換したためにdayjs objを渡してしまったままの箇所がないか、よくご確認ください。


ありがとう。サラバmoment.js。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?