JavaScriptのDateクラスでのISO8601とUNIXタイムスタンプについて
YoutubeとFlickrのAPIから受け取ったJSONを扱っててちょっとつまづきました。動画や写真の投稿日時に、YoutubeではISO8601が、FlickrではUNIXタイムスタンプが使われていて、そのままDateクラスに渡したところInvalid Date
となりました。
解決方法
ISO8601
new Date('2009-07-31T15:22:16.000Z');
実はFirefoxとChromeでは動いてました。が、SafariではInvalid Date
となってしまいました。ISO8601としては割と標準的な記述だと思うんですが、Safariでは対応してないようです。
- HTML5互換のISO-8601日付フォーマットライブラリ書いた。 - IT-Walker on hatena
- [JSAN] Date.W3CDTF - ISO-8601日時フォーマット対応JavaScriptクラス
ISO8601な記述を受けてDateやDateを継承したオブジェクトを返すライブラリがありました。今回はISO8601な文字列を扱うのは1回だけだったし、Dateオブジェクトを返してくれる方が良いかなと思ったので、ISO8601.jsを使いました。
UNIXタイムスタンプ
new Date( 1249053736 * 1000 );
JavaScriptは時間をミリ秒単位で扱っているらしく、UNIXタイムスタンプをミリ秒にしたものなら、通りました。
解説
ISO8601
var dobs = [ "1975-10-27T00:00:00Z", "1975-10-27T00:00:00+09:00", "1975-10-27T00:00:00", "1975-10-27 00:00:00", "1975/10/27T00:00:00Z", "1975/10/27T00:00:00+09:00", "1975/10/27T00:00:00", "1975/10/27 00:00:00" ]; for (var idx in dobs) { if (typeof dobs[idx] === 'string') { var dob = new Date(dobs[idx]); console.log(dob.toString()); } }Dateオブジェクトの挙動の違い - ペイパー・プログラマーズ・ダイアリー
色々と調べたところ、詳しく挙動を調査してるエントリーがありました。上記の結果はリンク先に書いてありますが、ISO8601的な記述はSafariではまったくだめ。FirefoxやChromeも完璧ではないようです。まぁISO8601って表記にかなり自由度があるししかたないのかも。
では方言としてのJavaScriptに対する標準語であるところのECMAScriptの仕様はどうなってるのか見てみます。現時点の最新は5th edition。
15.9.1.15 Date Time String Format
ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 Extended Format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZISO 8601 拡張フォーマットをベースに定義されているようですね。この観点からするとGoogle Chromeが「"YYYY-MM-DDThh:mm:ss±hh:mm"」を解釈してくれないのは残念ですね。この形式を解釈してくれるのはFirefoxだけです。
Dateオブジェクトの挙動の違い - ペイパー・プログラマーズ・ダイアリー
おなじエントリーからですが、ECMAScriptの仕様ではISO8601が読めてもおかしくなさそうなので、Safariが対応不足って事なのかな。ISO8601拡張フォーマットってのがなんだかよくわからないけど。
そもそもJavaScriptは"new Date(dateString)"におけるdateStringについて
dateString 日時を表す文字列。この文字列は parse メソッドで認識される書式である必要があります。
Date - JavaScript | MDNとされてるよう。
じゃあ"parse メソッドで認識される書式"とはなんぞやというと与えられた日時を表す文字列に対し、parse は時刻の値を返します。このメソッドは IETF 標準日付構文 "Mon, 25 Dec 1995 13:30:00 GMT" を受け付けます。また、アメリカ大陸のタイムゾーンの省略形は理解しますが、一般的な利用では例えば "Mon, 25 Dec 1995 13:30:00 GMT+0430" (グリニッジ標準時より 4 時間 30 分東) というようにタイムゾーンのオフセットを使ってください。タイムゾーンを指定しなかった場合、地方時のタイムゾーンと仮定します。GMT と UTC は同じとみなされます。
Date.parse() - JavaScript | MDNIETF 標準日付構文かぁー。あまり馴染みないですよね、とくに日本なら。
Dateオブジェクトの挙動の違い - ペイパー・プログラマーズ・ダイアリー
さらに同じところのエントリーからですが、Mozillaの情報ではparse()
で認識される書式という事で、IETF標準日付構文というのがその書式らしいです。Firefoxでnew Date().toString()
とかすると出てくる文字列ですね。これも引用元に調査結果がありますが、こちらは概ねサポートされてるみたいです。
W3C-DTF
国際標準化機構(ISO)においてISO 8601:1988[ISO8601](翻訳版がJIS X 0301-1992)が定められました。ただ、この標準はかなり多くのバリエーションを定義している上、西暦年の上2桁の省略を認めているため、あまり使い勝手が良くありません。そこで、IS0 8601のサブセットとして、日時の表記方法を限定し、よりシンプルにしたものがW3Cからノート[W3CDTF]として公開されました。
日付の表記に関するノート
ISO8601の書き方にバリエーションがありすぎるといった様な事から、ISO8601の一部を使ってW3C-DTFという仕様が出てるようです。見た目はISO8601だけど、ISO8601で許される一部の書き方が駄目になってるって事ですね。
Invalid Date
new Date( 'foo' ) === 'Invalid Date'
Dateクラスが解釈できない引数でnewするとInvalid Date
という文字列が返ってきました。とりあえず手元のブラウザでは大体そうだったし、検索して回ってもそれであってるっぽいです。でも、Dateオブジェクトの生成失敗をこれで判別しても良いんだろうか?一応try catch
で例外が取れないかなとも思ったんですが、取れなかったし、例外出てればcatchしてなくてもコンソールに出ますよね。if ( new Date( 'foo' ) !== 'Invalid Date' )
みたいなのが、どのブラウザでもちゃんと動くのかちょっと心配。