JavaScript の Date は罠が多すぎるの続き。そして Moment.js を使ってみた。

# JavaScript の Date は罠が多すぎるの続き

JavaScript の Date オブジェクトは意外なところでハマることがあります。
次の記事が役に立ちました。

[JavaScript の Date は罠が多すぎる - Qiita](http://qiita.com/labocho/items/5fbaa0491b67221419b4)

この記事に書かれていないことで、自分がハマったことを書き足したいと思います。

## new Date や Date.parse でタイムゾーン指定なし文字列をパースすると UTC で扱われたり扱われなかったり

```js
Date.parse("2016-05-01") 
=> 2016-05-01 00:00 UTC (2016-05-01 09:00 JST)
Date.parse("2016-05-01T00:00") 
=> 2016-04-30 15:00 UTC (2016-05-01 00:00 JST)
Date.parse("2016/05/01") 
=> 2016-04-30 15:00 UTC (2016-05-01 00:00 JST)
Date.parse("2016/05/01 00:00") 
=> 2016-04-30 15:00 UTC (2016-05-01 00:00 JST)
(Firefox 46.0 で確認)
```

同じ日時を指定しているのに違う日時になってしまう。

詳しいことはこちら。
[Date.parseとタイムゾーン - メモログ](http://memolog.org/2013/10/date_parse_and_timzone.html)

結論：パースするときに使う文字列はタイムゾーン指定を含めること。

## toString や toDateString で書式を指定できない

これは意外です。書式を指定して日付を文字列にする機能が Date オブジェクトに実装されていないんですね。
ちょっと調べると getFullYear 、getMonth 、getDate を使って自作する仕方が紹介されています。標準で欲しい機能ですね。

## Date.toJSON や JSON.stringfy すると UTC で返される

```js
var dt = new Date("2016-05-01T00:00+0900");
dt.toJSON() => 2016-04-30T15:00:00Z
```

タイムゾーン指定を見落とすと、指定した日時と異なる結果が返ったように見えます。

## toLocaleString で使われるタイムゾーンはパースするとき指定したタイムゾーンでない

```js
var dt = new Date("2016-05-01T00:00+0900");
dt.toLocaleString() => 2016/5/1 0:00:00 (日本標準時で実行した場合)
dt.toLocaleString() => 2016/4/30 11:00:00 (アメリカ東部夏時間で実行した場合)
dt.toLocaleString() => 2016/4/30 15:00:00 (heroku で実行した場合)
```

実行した環境のタイムゾーン指定が使われるようです。
ローカル機のブラウザで実行するときは問題ありませんが、クラウドサービスのサーバ機で実行するときは注意する必要ありです。

## getDate や getHours はパースするとき指定したタイムゾーンで値を返すわけでない

```js
var dt = new Date("2016-05-01T00:00+0900");
dt.getDate() => 1 (日本標準時で実行した場合)
dt.getDate() => 30 (アメリカ東部夏時間で実行した場合)
dt.getDate() => 30 (heroku で実行した場合)
```

前述の toLocaleString と同じ。

# Moment.js を使ってみた

前述のような JavaScript の Date オブジェクトの不便なところを解消するため、Moment.js を使います。

参考 [JavaScriptで日付を扱うならこれ！「moment.js」 : アシアルブログ](http://blog.asial.co.jp/1158)

公式 [Moment.js](http://momentjs.com/)

## Moment.js を使ってみた

* Moment.js 2.13.0

## ブラウザで使用する

以下のページからダウンロードします。
[Moment.js | Home](http://momentjs.com/)

以下のファイルをワークスペースにコピーします。

```
lib
    moment.js
```

使用します。

```html
    <script src="lib/moment.js" type="text/javascript"></script>  
```

## Node.js アプリで使用する

Node.js アプリのワークスペースにインストールします。

```
npm install --save moment 
```

使用します。

```js
var moment = require('moment');
```

## パースする

代表的なパースの仕方。Date と moment と併記します。

```js
var dt = new Date();
var dt = moment();
```

```js
var dt = new Date("2016-5-1");
var dt = moment("2016-5-1");
```

```js
var dt = new Date(2016, 5, 1);
var dt = moment([2016, 5, 1]);
```

## 書式を指定して日時を文字列にする

Date オブジェクトにない機能です。

```js
var dt = moment();
var buf = dt.format("YYYY/MM/DD");
```

## 指定したタイムゾーンの日時を取得する

```moment.format()``` で取得される日時は、```Date.toString()``` と同じく、実行した環境のタイムゾーン指定が使われます。

```js
var dt = moment("2016-05-01T00:00+0900");
dt.format() => 2016-05-01T00:00:00+09:00 (日本標準時で実行した場合)
dt.format() => 2016-04-30T11:00:00-04:00 (アメリカ東部夏時間で実行した場合)
```

```moment``` オブジェクトはタイムゾーンを指定して保持できます。ここが ```Date``` オブジェクトと違います。

```js
dt.utcOffset("+0900");
dt.format() => 2016-05-01T00:00:00+09:00 (日本標準時で実行した場合)
dt.format() => 2016-05-01T00:00:00+09:00 (アメリカ東部夏時間で実行した場合)
```

```moment.utcOffset()``` はタイムゾーン指定を含む日時の文字列を指定してもいい。これは意外と便利です。

```js
var buf = "2016-05-01T00:00+0900";
var dt = moment(buf).utcOffset(buf);
```

## 同じ日時か判定する

```moment``` オブジェクトは便利な関数を持っています。
例えば日時を比較して同じか判定するのも簡単です。

```js
moment("2016-05-01T00:00+0900").isSame("2016-05-01T00:00+0900", "day");
```