JSの日付処理でハマった話

どんなプログラムでも、日付を処理する場面があると思います。
JavaScriptの日付処理でハマった点を、参考までに紹介します。

基本の「キ」

JavaScriptで現在日時を取得するには、例えば、

var nowOS = new Date();

のように書きますが、これは、実行環境における現在日時です。
そこで、OSのタイムゾーンがUTCとどのくらい差があるかを調べます。

var offset = nowOS.getTimezoneOffset();

このように書くと、OSのタイムゾーンから見て、UTCが何分、どうなっている(戻っている or 進んでいる)のかが分かります。

offset = offset * 60 * 1000;

ついでに、60と1000を掛けておきます。UTCとのズレは、分単位でしか分からないため、1分=60秒、そして、PCの時間の最小単位が、1000分の1秒なので、このようにします。(1/1000秒は、1ミリ秒と言います)

次に、現在日時が、UTCの、1970年1月1日 00時00分00秒から、何ミリ秒経過しているかを計算します。

この時、offset=0 であれば、実行環境はUTCであり、そうでなければ、OSに設定されたタイムゾーンということになります。

/* 実行環境がUTCのとき(offset=0)*/
var time = nowOS.setTime(nowOS.getTime() + 540*60*1000);
 
/* 実行環境が現地時間のとき(offset<>0)*/
var time = nowOS.setTime(nowOS.getTime());

ポイントは、OSがローカル環境なら、nowOSの経過秒数をそのまま使い、UTCのときは、日本時間はUTCから見ると、プラスの9時間なので、差分の540分に、60と1000を掛けて加算します。

応用

次に、日付を文字列で取得する方法です。

/* 1.実行環境がUTCのとき */
var dateStr = new Date(time).toISOString();
 
/* 2.実行環境が現地時間のとき */
var dateStr = new Date(time - offset).toISOString();

ここが、ハマりポイントです。
例えば、生成したDateオブジェクトを変数に入れて、日数や時間を加算減算し、その変数に対して toISOString() を実行すると、加算減算された値は維持されるものの、その値から割り出された「UTC」の日付文字列が返ります!
これは、Oh My God ! ! です。

では、どうするか。
さきほど求めた、経過ミリ秒数 (time) を使います。
(上記コードの2.です)
new Date に time を引数として渡すのですが、time だけ渡すと、OSは、プラス9時間の時差があることを分かっているため、自動的に9時間戻してしまいます。そこで、time からもう一度、offset を引いて、強引に、18時間進んでいることにします。こうして生成した new Date に toISOString() を実行すると、9時間分だけ戻って、日本時間の日付文字列が返ります。

応用2

仮に、日本時間の現在日時から、丸4日後の日付文字列が欲しいとします。

var oneDay = 24 * 60 * 60 * 1000;
 
var newDateStr = new Date(time + 4 * oneDay - offset).toISOString();

上記のように書くと取得できます。
まず、変数 oneDay に、丸1日分のミリ秒数を格納します。
(24時間 × 60分 × 60秒 × 1000ミリ秒)
そのうえで、変数 time に、4日分の oneDay を足し、offset を引く。
これを new Date の引数に渡して、toISOString() を実行すればよいです。
(ただし、offset を引くのは、OSがローカル環境の場合のみ)

ぜひ、参考にしてください。


この記事が気に入ったらサポートをしてみませんか?