15

私たちのクライアントは、日付と時刻の値をデータベースとまったく同じようにブラウザーに表示したいと考えており、それらを UTC としてデータベースに保存しています。

最初は、シリアライゼーションと Javascript 側でいくつかの問題がありました。DateTime 値が 2 回シフトされました。最初はマシンのローカル タイム ゾーンに一致し、次にブラウザのタイム ゾーンに一致します。カスタム コンバーターを JavaScriptSerializer に追加することで、この問題を修正しました。Serialize オーバーライドで DateTime を DateTimeKind.Utc としてマークしました。Serialize からデータをフィードバックするのは少し大変でしたが、同じ JavaScriptSerializer /Date(286769410010)/ 形式で DateTime 値を返すのに役立つ Uri ハックが見つかりましたが、現地時間にシフトすることはありませんでした。Javascript 側では、KendoUI JS ライブラリにパッチを適用して、構築された Date() オブジェクトをオフセットし、それらが UTC であるかのように表示されるようにしました。

次に、反対側のデシリアライゼーションに取り組み始めました。ここでも、JSON.stringify の代わりにカスタム stringify を使用するようにコードを調整する必要がありました。これは、現地時間から UTC に変換するときにデータをオフセットします。これまでのところ、すべてが順調に見えました。

しかし、このテストを見てください:

    public void DeserialiseDatesTest()
    {
        var dateExpected = new DateTime(1979, 2, 2,
            2, 10, 10, 10, DateTimeKind.Utc);

        // this how the Dates look like after serializing
        // anothe issue, unrelated to the core problem, is that the "\" might get stripped out when dates come back from the browser
        // so I have to add missing "\" or else Deserialize will break
        string s = "\"\\/Date(286769410010)\\/\"";

        // this get deserialized to UTC date by default
        JavaScriptSerializer js = new JavaScriptSerializer();

        var dateActual = js.Deserialize<DateTime>(s);
        Assert.AreEqual(dateExpected, dateActual);
        Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind);

        // but some Javascript components (like KendoUI) sometimes use JSON.stringify 
        // for Javascript Date() object, thus producing the following:
        s = "\"1979-02-02T02:10:10Z\"";

        dateActual = js.Deserialize<DateTime>(s);
        // If your local computer time is not UTC, this will FAIL!
        Assert.AreEqual(dateExpected, dateActual);

        // and the following fails always
        Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind); 
    }

\/Date(286769410010)\/JavaScriptSerializerが文字列を UTC 時間ではなく1979-02-02T02:10:10Zローカル時間にデシリアライズするのはなぜですか?

カスタムに Deserialize メソッドを追加しようとしましたJavascriptConverterが、問題は、JavascriptConverter に次の型がある場合、Deserialize が呼び出されないことです。

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
    }

SupportedTypesDeserialize は、 DateTime フィールドを持ついくつかの複雑なエンティティの型が含まれている場合にのみ呼び出されると思います。

したがって、2 つの矛盾がありますJavaScriptSerializerJavascriptConverter

  • Serialize では、すべてのデータ項目について、SupportedTypes の単純型が考慮されますが、Deserialize は、単純型についてはそれを無視します
  • Deserialize は、一部の日付を UTC として、一部を現地時間として逆シリアル化します。

これらの問題を解決する簡単な方法はありますか? 私たちがJavaScriptSerializer使用しているサードパーティのライブラリの一部は、JavaScriptSerializer.

4

1 に答える 1

44

JavaScriptSerializer、そしてDataContractJsonSerializerバグだらけです。代わりにjson.netを使用してください。Microsoft でさえ、ASP.Net MVC4 やその他の最近のプロジェクトでこの切り替えを行いました。

この/Date(286769410010)/形式は独自のものであり、Microsoft によって作成されています。問題があり、広くサポートされていません。1979-02-02T02:10:10Zどこでもこの形式を使用する必要があります。これは、ISO8601およびRF3339で定義されています。機械と人間の両方が読み取り可能で、語彙的にソート可能で、カルチャに不変で、明確です。

JavaScript では、新しいブラウザーで実行することが保証できる場合は、次を使用します。

date.toISOString()

ここを参照してください

クロスブラウザーと古いブラウザーの完全なサポートが必要な場合は、代わりにmoment.jsを使用してください。

アップデート

余談ですが、本当に を使い続けたい場合はJavaScriptSerializer、 に逆シリアル化することができますDateTimeOffset。これにより、正しい時間が保持されます。DateTime次のように、そこからUTC を取得できます。

// note, you were missing the milliseconds in your example, I added them here.
s = "\"1979-02-02T02:10:10.010Z\"";

dateActual = js.Deserialize<DateTimeOffset>(s).UtcDateTime;

これでテストに合格します。

于 2013-06-12T15:57:52.630 に答える