2013-06-12 9 views
10

発行します。JavaScriptSerializer UTCのDateTimeは、私たちのクライアントは、彼らがデータベース内にあるとおりに、ブラウザに日付と時刻の値を表示したかった、と私たちは、データベース内のUTCとしてそれらを格納している

まずはシリアライズとJavascriptの側でいくつかの問題を抱えていました。 DateTimeの値は、最初にマシンのローカルタイムゾーンと一致するように2回シフトされ、ブラウザのタイムゾーンと一致します。カスタムコンバーターをJavaScriptSerializerに追加することで修正しました。 DateTimeは、SerializeオーバーライドでDateTimeKind.Utcに設定されています。バックのSerializeからデータを供給するために少し大変だったが、我々はいくつかのウリは、同じJavaScriptSerializer /日(286769410010)/フォーマットではなく現地時間に移行することなく、DateTimeの値を返すために役立っているハックました。 Javascript側では、構築されたDate()オブジェクトをオフセットするためにKendoUI JSライブラリにパッチを適用し、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); 
    } 

なぜJavaScriptSerializerは現地時間に\/Date(286769410010)\/ UTC時刻に文字列が、1979-02-02T02:10:10Zをデシリアライズしますか?

私たちは、カスタムJavascriptConverterに逆シリアル化メソッドを追加しようとしましたが、問題は、私たちのJavascriptConverterには次の種類がある場合はデシリアライズが呼び出されないということです。

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

私は推測する、デシリアライズのみSupportedTypes場合に呼び出されますDateTimeフィールドを持つ複雑なエンティティのいくつかの種類が含まれています。

  • デシリアライズはUTCといくつかのように、いくつかの日付をデシリアライズ
  • Serializeをアカウントにすべてのデータ項目のSupportedTypesでシンプルなタイプがかかりますが、逆シリアル化は、単純型のためにそれを無視します:

    ので、JavaScriptSerializerJavascriptConverterは2つの矛盾を持っています - 現地時間として。

これらの問題を解決するための任意の簡単な方法はありますか? JavaScriptSerializerをいくつかの他のシリアライザと置き換えるのは少し怖いです。私たちが使っているサードパーティのライブラリのいくつかは、ある種の "機能/バグ"であるJavaScriptSerializerに依存しているかもしれないからです。

答えて

36

JavaScriptSerializerおよびDataContractJsonSerializerにはバグがあります。代わりにjson.netを使用してください。マイクロソフトでさえASP.Net MVC4やその他の最近のプロジェクトでこの切り替えを行っています。

/Date(286769410010)/フォーマットは独自およびMicrosoftによって構成されています。それには問題があり、広くサポートされていません。どこでも1979-02-02T02:10:10Z形式を使用する必要があります。これは、ISO8601RF3339で定義されています。これは機械と人間の両方で読み取り可能で、語彙的にソート可能であり、文化は不変であり、曖昧ではありません。JavaScriptで

、あなたが使用し、その後、新しいブラウザ上で動作していることを保証できる場合:

date.toISOString() 

Reference here

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

UPDATE

あなたが本当にJavaScriptSerializerを使用し続けたい場合は、あなたは正しい時刻を維持するだろうDateTimeOffsetにデシリアライズすることができます。

// 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; 

あなたのテストはパスします:次のように、その後、そこからUTC DateTimeを得ることができます。

+1

Ok - これはすべてうまくいいものですが、より良いjsonライブラリを出荷してバグのJavaScriptSerializerだけを残すのではなく、Msftの言い訳は何ですか? – nothingisnecessary

関連する問題

 関連する問題