LoginSignup
76

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-05-08

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");

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
76