JSON データのデシリアライズにおける日付型の変換

(軽めの 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 データをデシリアライズして、確認のためにブラウザーで表示してみます。

JSON データ (ISO 8601 形式)

表示サンプル

ここでは、先頭部分が 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 サービスで返すと次のようになります。表示結果は同じです。

JSON データ (ASP.NET 形式)

■ その他の場合

その他にも、日付の形式が案件で指定されている場合や、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 データ (カスタム形式)

作成したサンプル
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

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。