Moment.js? Day.js? Javascirpt? Temporal?

Javascript では日付関連の操作をする `Date` オブジェクトがありましたが API が使いづらいので [Moment.js](https://momentjs.com/) を使うのがメジャーでした。ただ、 Moment.js は翻訳ファイルを含みファイルサイズが大きく、 代替として [DAYS.JS](https://day.js.org/) などが登場します。また、昨今登場予定の Temporal などがあります。ここら辺の状況をまとめてみたいと思います。


### `Date` オブジェクトは本当に使いにくい？
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date

こちらにまとまっていますが、ざっと見てみると使いにくさはあるものの、巨大なライブラリを使うほどでもない可能性があります。

```javascript
Date.prototype.getDate()
    // 地方時に基づき、指定された日時の「日」 (1–31) を返します。
Date.prototype.getDay()
    // 地方時に基づき、指定された日時の「曜日」 (0–6) を返します。
Date.prototype.getFullYear()
    // 地方時に基づき、指定された日時の「年」 (4桁の年であれば4桁) を返します。
Date.prototype.getHours()
    // 地方時に基づき、指定された日時の「時」 (0–23) を返します。
Date.prototype.getMilliseconds()
    // 地方時に基づき、指定された日時の「ミリ秒」 (0–999) を返します。
Date.prototype.getMinutes()
    // 地方時に基づき、指定された日時の「分」 (0–59) を返します。
Date.prototype.getMonth()
    // 地方時に基づき、指定された日時の「月」 (0–11) を返します。
Date.prototype.getSeconds()
    // 地方時に基づき、指定された日時の「秒」 (0–59) を返します。
```

基本的なGetterは備えてます。
注意事項は`getMonth()`は0始まりだということはあります。これはJavaからの影響だそうです。

```javascript
var Xmas95 = new Date('December 25, 1995 23:15:30');
var month = Xmas95.getMonth();

console.log(month); // 11
```

Setterも備えてます。

```javascript
Date.prototype.setDate()
    // 地方時に基づき、指定された日時の「日」を設定します。
Date.prototype.setFullYear()
    // 地方時に基づき、指定された日時の「年」を完全な形 (例えば、4桁の年であれば4桁) で設定します。
Date.prototype.setHours()
    // 地方時に基づき、指定された日時の「時」を設定します。
Date.prototype.setMilliseconds()
    // 地方時に基づき、指定された日時の「ミリ秒」を設定します。
Date.prototype.setMinutes()
    // 地方時に基づき、指定された日時の「分」を設定します。
Date.prototype.setMonth()
    // 地方時に基づき、指定された日時の「月」を設定します。
Date.prototype.setSeconds()
    // 地方時に基づき、指定された日時の「秒」を設定します。
```

Localeも対応しています。

```javascript
Date.prototype.toLocaleDateString()
    // システム設定の日時の「日付」部を、地域の日付書式に従った文字列に変換して返します。
Date.prototype.toLocaleFormat()
    // 書式化された文字列を使って、日時を文字列に変換します。
Date.prototype.toLocaleString()
    // 日付を地域の日付書式に従った文字列に変換して返します。Object.prototype.toLocaleString() メソッドを上書きします。
Date.prototype.toLocaleTimeString()
    // システム設定の日時の「時刻」部を、地域の日付書式に従った文字列に変換して返します。
```

意外と必要な操作はできます。特に必要になるまではライブラリは使わなくてもいいもしれません・・・

### javascriptとMoment.jsとDAY.JS比較

javascript

```javascript
new Date().getDate()
```

Moment.js

```javascript
moment().date()
```

DAY.JS

```javascript
dayjs().date()
```

Moment.jsとDAY.JSはほぼ変わらないインターフェースを持っています。`month()`はjavascriptと同じく0始まりなのは注意が必要です。

javascript、そのままとの大きな違いは、add() や weekdays() などの便利なメソッドがあることです。特にadd()などの時間の計算は便利なので時間の計算を使う場合はライブラリを検討したほうがいいかもしれません。

Moment.js

```javascript
moment().add(7, 'days'); 
// 7日を足す

moment().weekday(-7); // last Monday
```

DAY.JSの場合はpluginをrequireする必要があります。

```javascript
dayjs().add(7, 'day')
// 7日を足す

var weekday = require('dayjs/plugin/weekday')
dayjs.extend(weekday)

dayjs().weekday(-7) // last Monday
```

### Moment.jsとDAY.JS比較

`weekdays()`などのメソッドは Moment.js にしかなさそうです。

```javascript
moment.weekdays(3)
// "Wednesday"
```

Timezoneの扱いも異なります。Moment.jsではかなり細かいTimezoneのサポートがありますが、DAYS.JSはpluginでの対応でISSUEは開いてますが、まだFIXはしてません。
https://momentjs.com/timezone/docs/
https://github.com/iamkun/dayjs/issues/323

これらの便利なメソッドやTimezoneのサポートが必要であれば Moment.js を検討しても良さそうです。

### Temporal とは？

Temporal とは ECMAScript を策定してる TC39 が新しく仕様を提案して、いまフィードバックを募集している仕様のことで、これが採用されれば標準ライブラリとして使えるようになります。 
https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/

実際のユースケースに適しているかのフィードバックを募集しているので、もし興味があれば是非フィードバックを送ってみてください。

```sh
npm install --save proposal-temporal
```

をした後requireすることで使えます。

```javascript
const { Temporal } = require('proposal-temporal');
```

API のドキュメントは下記です。
https://tc39.es/proposal-temporal/docs/

既存のライブラリとの違いとしては、Dealing only with immutable objectsとあり、immutableであり、あとから時間情報の変更ができないことが、まず特筆されます。これは非常に便利そうです。

ConsoleにてTempralを呼び出すと下記のような感じです。

<img width="501" alt="スクリーンショット 2020-07-14 22.07.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/ada26d4f-2e10-1f37-c911-a8b132928d14.png">

TimeZoneとDateTimeとDateとTimeがそれぞれ分かれているのは便利そうな感じがします。


```javascript

// IANA time zone names and UTC offsets
tz = Temporal.TimeZone.from('UTC');
tz = Temporal.TimeZone.from('Africa/Cairo');
tz = Temporal.TimeZone.from('america/VANCOUVER');
tz = Temporal.TimeZone.from('Asia/Katmandu');  // alias of Asia/Kathmandu
tz = Temporal.TimeZone.from('-04:00');
tz = Temporal.TimeZone.from('+0645');


// Converting a specific absolute time to a calendar date / wall-clock time
timestamp = new Temporal.Absolute(1553993100000000000n);
tz = new Temporal.TimeZone('Europe/Berlin');
tz.getDateTimeFor(timestamp);  // => 2019-03-31T01:45
tz.getDateTimeFor(timestamp).day;  // => 31
```

こんな感じでTimeZoneを扱えます。

```javascript
date = Temporal.Date.from('2006-08-24');
date.plus({years: 20, months: 4})  // => 2026-12-24
```

日付の計算はこのような感じです。
こうした仕様が確定してくると、ひょっとすると Moment.js や DAY.JS を使わない日が来るかもしれません。
（似たようなTempralのWrapperライブラリが出るかもしれません）