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

  • 23
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

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

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

JavaScript の Date は罠が多すぎる - Qiita

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

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

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とタイムゾーン - メモログ

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

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

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

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

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

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

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

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 はパースするとき指定したタイムゾーンで値を返すわけでない

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」 : アシアルブログ

公式 Moment.js

Moment.js を使ってみた

  • Moment.js 2.13.0

ブラウザで使用する

以下のページからダウンロードします。
Moment.js | Home

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

lib
    moment.js

使用します。

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

Node.js アプリで使用する

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

npm install --save moment 

使用します。

var moment = require('moment');

パースする

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

var dt = new Date();
var dt = moment();
var dt = new Date("2016-5-1");
var dt = moment("2016-5-1");
var dt = new Date(2016, 5, 1);
var dt = moment([2016, 5, 1]);

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

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

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

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

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

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 オブジェクトと違います。

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

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

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

同じ日時か判定する

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

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