(軽めの jQuery Advent Calendar 2012 の 23 日目です。)
次のようなコードで jQuery の getJSON 関数で JSON Web サービスを呼び出すと、
コールバック関数の引数 data には JSON データがデシリアライズ (パース) されたオブジェクトが渡されます。
ここで、data に含まれている値の型について考えてみます。
$.getJSON("Services/Products")
.done(function (data) {
// 取得したデータに対する処理
var value = data[0].prop1; // 何型?
});
JSON 形式では、オブジェクト、配列、文字列、数値、ブール値、null の記法が定義されており、
それぞれ JavaScript の Object, Array, String, Number, Boolean, null の値に対応します。
しかし、Date に対応する日付型は定義されていません。
getJSON 関数では、JSON 形式の文字列をデシリアライズするために
既定では $.parseJSON 関数 (JSON.parse 関数を IE7 以前のために拡張したもの) を使用します。
この場合、たとえ ISO 8601 の日付形式である "2012-12-24T14:59:59.999Z" のような文字列であっても、
自動的に Date 型に変換されることはありません。
しかし jQuery の Ajax 機能の設定値の中に converters というものがあり、
デシリアライズ方法をカスタマイズできるようになっています。
この機能は、jQuery 1.5で追加されたようです。
今回は、この converters を利用して日付を表す文字列を Date 型に変換してみます。
■ ISO 8601 の日付形式の場合
converters を設定するには、Ajax で通信を開始する前に $.ajaxSetup 関数を呼び出します。
キー "text json" に対してデシリアライズ関数を指定します。
次のように実装します。
$.ajaxSetup({
converters: {
"text json": function (text) {
return JSON.parse(text, reviveDate);
}
}
});function reviveDate(key, value) {
if (value == null ||
value.constructor !== String ||
value.search(/^\d{4}-\d{2}-\d{2}/g) === -1)
return value;
return new Date(value);
}
実は JSON.parse 関数の第 2 引数には、キーと値を受け取って任意の値に変換する関数を指定できます。
この reviveDate 関数の中で、正規表現で文字列の先頭部分が YYYY-MM-DD に一致した場合は Date 型に変換しています。
次のように $.ajaxSettings.converters に直接上書きしても同様の効果です。
$.ajaxSettings.converters["text json"] = function (text) {
return JSON.parse(text, reviveDate);
};
また、$.getJSON 関数ではなく $.ajax 関数を使う場合は、引数 settings に converters を指定できます。
では実際に次の JSON データをデシリアライズして、確認のためにブラウザーで表示してみます。
ここでは、先頭部分が YYYY-MM-DD の形式かどうかを判定しましたが、
他にも例えば「key がサフィックスとして "Date" を持つ (例: startDate)」という判定条件も考えられるでしょう。
なお、IE で Date のコンストラクターに ISO 8601 の日付形式を指定できるのは、IE9 以降です。
■ ASP.NET の場合
JSON Web サービスを WCF サービスなどで実装する場合、
.NET Framework の DateTime 型のオブジェクトは
"\/Date(1356361199999)\/" または "\/Date(1356361199999+0900)\/" のような形式にシリアライズされます。
したがって、先ほどの reviveDate 関数を次のように実装します。
function reviveDate(key, value) {
if (value == null ||
value.constructor !== String)
return value;
var m = /^\/Date\((\d+)(.+)?\)\/$/g.exec(value);
if (!m) return value;
return new Date(parseInt(m[1]));
}
先ほどと同じ意味のデータを WCF サービスで返すと次のようになります。表示結果は同じです。
■ その他の場合
その他にも、日付の形式が案件で指定されている場合や、ISO 8601 形式を IE8 でも使いたい場合などが考えられますが、
同様に変換ロジックをカスタマイズすれば実現できると思います。
例えば、"2012年12月24日" という形式の場合は、次のようにして実現できます。
function reviveDate(key, value) {
if (value == null ||
value.constructor !== String)
return value;
var m = /^(\d{4})年(\d{1,2})月(\d{1,2})日$/g.exec(value);
if (!m) return value;
return new Date(parseInt(m[1]), parseInt(m[2]) – 1, parseInt(m[3]));
}
これで、次のようなデータを変換できます。
作成したサンプル
JSON Converter Sample 1 (ISO 8601 形式)
JSON Converter Sample 2 (ASP.NET 形式)
JSON Converter Sample 3 (カスタム形式)
バージョン情報
JSON.parse 関数: Internet Explorer 8 以降、その他の主要なブラウザー
ISO 8601 形式を受け取る Date のコンストラクター: Internet Explorer 9 以降、その他の主要なブラウザー
参照
jQuery.ajax()
Extending Ajax: Prefilters, Converters, and Transports
JSON の紹介
Date and Time Formats (W3C)
jQuery parseJSON automatic date conversion for Asp.net and ISO date strings