JavaScriptのDateで表現可能な過去と未来
寒くなったり暖かくなったりと気温変化が激しかったためか、先週一週間は体調を崩してしまい仕事がはかどらなかった。一日だけ休んだが、熱があるわけでもなく、ちょっと頑張れば出勤はできるし、重要な会議もあった。しかし、全身脱力感で、何もする気が起こらない。そんなボーっとした頭の状態で、ある規格書を読んでいたら、イベントの開始時刻にJavaScriptのDateクラスを使っていた。普通なら気になることはなかったが、このときに限りDateで表現できる最大の未来はいつだ?ということが気になってしまった。もちろん、それは遠い未来であり、人類が気にするようなスケールの時間でないことは知っている。気になったのは、各ブラウザが正しく実装されているかということ。
以下のブラウザで確認してみた。IEはよく知らないが、それ以外のブラウザは最新のはずだ。
Firefox | Chrome | Safari | Opera | IE |
---|---|---|---|---|
3.6.4 | 5.0.375.17 dev | 4.0.5 | 10.51 | 8.0.6001 |
結論から言うと、Dateで表現できる日時は、いずれのブラウザもECMA262規格通りに正しく実装されていた。
しかし、そのECMA262規格がイマイチ納得し難いものだ。以下のような記述がある。
ECMAScript Number values can represent all integers from -9,007,199,254,740,991 to 9,007,199,254,740,991; this range suffices to measure times to millisecond precision for any instant that is within approximately 285,616 years, either forward or backward, from 01 January, 1970 UTC.
これはこれでよい。9,007,199,254,740,991
という数値の意味は「JavaScriptの大きな数と小さな数の仕組みを理解する 〜IEEE754入門〜」で解説したが、正確に表現できる最大の整数である。
しかし、Dateの有効範囲はECMA規格では以下のように絞られている。
The actual range of times supported by ECMAScript Date objects is slightly smaller: exactly -100,000,000 days to 100,000,000 days measured relative to midnight at the beginning of 01 January, 1970 UTC. This gives a range of 8,640,000,000,000,000 milliseconds to either side of 01 January, 1970 UTC.
1970年1月1日のEpoch時刻を基準にして前後1億日に絞ることにどういう意味があるのだろうか。どうせ絞るなら計算が閉じるように絞ればよかったと思う。
つまり、d1, d2が有効なDateオブジェクトのとき、その差(d1-d2)の計算も有効になるようにすべきだと思う。
tm = 8.64e+15; d1 = new Date(tm); p1 = d1 - new Date(-tm); // 17280000000000000 p2 = d1 - new Date(-tm + 1); // 17280000000000000 p3 = d1 - new Date(-tm + 2); // 17279999999999998 p4 = d1 - new Date(-tm + 3); // 17279999999999996
このように、整数で正確に表現できる範囲を超えてしまい結果は正しくない。整数で表現できる最大数の半分の値を有効範囲とすればよかったのではと思う。
最後になったが、各ブラウザで下記のような動作が確認できたので、Dateで表現可能な時刻の範囲はECMA規格通りと考えられる。
tm = 8.64e+15; d1 = new Date(tm); // Sat Sep 13 275760 09:00:00 GMT+0900 d2 = new Date(tm + 1); // Invalid Date d3 = new Date(-tm); // Tue Apr 20 -271821 09:00:00 GMT+0900 d4 = new Date(-tm - 1); // Invalid Date
有効範囲を超えたときのDateオブジェクトのvalueOf()やgetTime(), getFullYear()などのメソッド結果は全てNaNを返す。toString()した結果の文字列はECMA規格では正確には規定されていないが、IE8では"NaN"という文字列だった。いくらなんでもそれはおかしいだろうと思う。また、紀元前の表現はIE8以外はマイナス符号がつくだけなのに対して、IE8はB.C.表記だった。こんなところもIEって独特だ。
以下、雑記
よく病気になって寝込んでいると、いろいろな悪夢的な妄想が半醒半睡状態のときに襲ってくる。だいたいは、こんがらかった糸を必死にほどこうとするが、もつれるばかりで全然ほどけない というパターンや、自分がやるべきことではない事を一所懸命にやっているが、次から次へとやる事が増えてきて、どうしようどうしようと悩んでいるというパターンだ。
今回はちょっと変わっていた。宇宙にはフラクタルのような入れ子構造や自己再帰構造があるが、どういうわけかECMAScriptの規格が宇宙の構造の一部に取り込まれたということを僕が気づいてしまった。宇宙の時刻はECMAScriptのDateオブジェクトで管理されている。Dateオブジェクトは当然有限未来までしか表現できないから、その先は宇宙は存在し得ないということを世界でただ一人僕だけが知ってしまった。このことを皆に知らせて何とかしなければと思う反面、27万5千年後のことだから、そのときは人類さえ存在しないかも知れないので、特に知らなくても何も問題ないというジレンマにうなされるという何ともへんてこりんなものだった。
ちなみに、僕は「リポビタンD」を飲むと効き目は抜群なようだ。普段は全く飲まないが、ちょっとした病気のときは1本飲んで寝ていると、半日程で気分が良くなる。タウリンの効果なのだろうか。今回もそれで良くなった。といっても飲む/飲まないの比較はできないのであくまで主観的なものではあるが。