web-dev-qa-db-ja.com

デシリアライズ中にJSON日付を.NET DateTimeに変換する適切な方法

JSONデータでMVCコントローラーを呼び出すjavascript関数があります。

var specsAsJson = JSON.stringify(specs);
$.post('/Home/Save', { jsonData: specsAsJson });

サーバー側では、コントローラー内で、このエラーを乗り越えることができないようです。

/ Date(1347992529530)/は、DateTimeの有効な値ではありません。

Deserialize()を呼び出すと、この例外が発生します(以下のメソッドの3行目)。

    public ActionResult Save(string jsonData)
    {
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() });
        var specs = serializer.Deserialize<List<EquipmentSpecWithParameterlessConstructor>>(jsonData);

        return View("Index", _allTrackerJobs);
    }

私はいくつかのグーグルを行ってきましたが、上記のコードはこの作業を行うための私の最新の試みです( here のTimeSpanJsonConverterを使用)。他のアプローチは、サーバーに日付のみを送信することを示していますが、いくつかのプロパティとして日付を持つオブジェクトのリストがあります。

これを解決するための一般的に受け入れられているエレガントなアプローチはありますか、それとも何らかのい回避策が必要ですか?これを解決する正しい方法は何ですか?

===================元の質問の終わり================== =


編集-JsonConvertを使用してシリアライズすることにより解決

以下の私のanswerを参照してください(この質問の安っぽい回避策ではありません)。


編集-安っぽい回避策

ドメインオブジェクトとまったく同じフィールドを使用してDTOを作成しましたが、日付フィールドの文字列を作成してデシリアライズしました。シリアル化を解除できるようになったので、日付を有効な形式に変換して、DTOからドメインオブジェクトを作成できるようにします。

public class EquipmentSpecDto
{
    public string StartTime { get; set; }
    public string EndTime { get; set; }
    // more properties here
}

そして、逆シリアル化にDTOを使用しただけです。

var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData);

編集2-JavaScriptの日付を.NETに変換する

完全を期すために、そして私が誰か他の人を1時間救うことを期待して、これがjavascriptの日付を変換する方法でした:

    foreach (EquipmentSpecDto specDto in specDtos)
    {
        // JavaScript uses the unix Epoch of 1/1/1970. Note, it's important to call ToLocalTime()
        // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
        DateTime unixEpoch       = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        Double startMilliseconds = Convert.ToDouble(specDto.StartTime.Substring(6, 13));
        Double endMilliseconds   = Convert.ToDouble(specDto.EndTime.Substring(6, 13));
        DateTime startTime       = unixEpoch.AddMilliseconds(startMilliseconds).ToLocalTime();
        DateTime endTime         = unixEpoch.AddMilliseconds(endMilliseconds).ToLocalTime();
        EquipmentSpec spec       = new EquipmentSpec(startTime, endTime, specDto.Equipment);

        specs.Add(spec);
    }
15
Bob Horn

簡単な答えを見つけました。私のJavaScriptでは、JavaScriptSerializerを使用してデータをシリアル化していました。多くのグーグル検索の後、私はこれを見つけました 記事 これは、JSONConvertを使用してシリアル化する方法を示し、これにより.NETにより適したDateTimeが使用されます。

古い:

_var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))
_

日付は次のようになります:Date(1348017917565)

新規:

_var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));
_

日付は次のようになります:_2012-09-18T21:27:31.1285861-04:00_

だから、問題は本当にそもそもどのようにシリアライズしていたかだった。 JsonConvertを使用すると、バックエンドでのシリアル化解除が正常に機能しました。

13
Bob Horn

このコードはインターネットで見つけました。それは私にとって魅力のように働いた...

function customJSONstringify(obj) {
    return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/")
}

JavaScriptの日付とさまざまなサーバー側言語との間の変換で人々を非常に頻繁にキャッチすることの1つは、両方の側がUNIXスタイルのタイムスタンプ値を理解できるかもしれないが、JSはマイクロ秒精度のタイムスタンプを使用するが、他のほとんどの言語ではデフォルトタイムスタンプの精度は秒です。

つまり、Javascriptの1347993132851を1000で割って、他の言語でUNIXタイムスタンプとして認識される必要があります。

あるいは、プラットフォームがフォーマットされた日付文字列を受け入れることができる場合、Javascript Date()オブジェクトを使用して、タイムスタンプ値をフォーマットされた日付に変換してサーバーに送信します。または、さらに良いことに、 Date.jsMoment.js などのヘルパーライブラリを使用します。

3
Spudley

私は@Bob Hornの回答を取りましたが、それは私にとってはうまくいきませんでした。私のRESTサービスはJavascritptの日付を使用しています。参照された回答を拡張メソッドに適合させました。


using System;

namespace Mediatel.Framework
{
    public static class JsonDate
    {
        public static DateTime ConvertToDateTime(this string jsonDate)
        {
            // JavaScript uses the unix Epoch of 1/1/1970. Note, it's important to call ToLocalTime()
            // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey.
            DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            Double milliseconds = Convert.ToDouble(jsonDate);
            DateTime dateTime = unixEpoch.AddMilliseconds(milliseconds).ToLocalTime();

            return dateTime;
        }
    }
}
2

エラーを受け取った後

/ Date(1347992529530)/は、DateTimeの有効な値ではありません。

この置換を使用するとうまくいきました。

var data = ko.toJSON({ objext: obj});
$.ajax({
    url: "/API/API.asmx/SaveObject",
    type: "POST",
    dataType: "json",
    contentType: "application/json; char-utf8;",
    data: data.replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/"),
    success: function (r) {},
    error: function (e) {},
    complete: function () {}
});
1
BunkerBilly

JavaScript(EcmaScript)は、ISO-8601標準の簡素化に基づいて、DateTime文字列交換形式を定義しています。

XMLスキーマは、ISO-8601に基づいたDateTime文字列交換形式も定義しています。

.NETクラスSystem.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTimeを使用して、.NET DateTime値からXML形式への変換およびその逆の変換を処理すると便利です。

JavaScriptは同じISO-8601標準に基づいているため、おそらくJSONの場合にも機能します。

1
dthorpe