2013-06-12 14 views
10

verir.JavaScriptSerializer UTC DateTime Müşterimiz onlar veritabanında tam olarak tarayıcıda tarih ve saat değerleri göstermek istedim ve biz veritabanında UTC olarak depoladığınız

İlk başta biz serileştirme ve Javascript tarafı bazı sorunlar vardı. DateTime değerleri, makinenin yerel saat dilimiyle eşleşmek için önce iki kez kaydırıldı ve ardından tarayıcıdaki saat dilimini eşleştirmek için. JavaScriptSerializer'a özel bir Dönüştürücü ekleyerek bunu düzeltdik. DateTime'ı Serialize geçersiz kılmada DateTimeKind.Utc olarak işaretledik. Verileri Serileştirme'den geri almak biraz zordu ama biz DateTime değerlerini aynı JavaScriptSerializer/Date (286769410010)/formatta döndürmeye yardımcı olan ancak yerel saate geçmeden yardımcı olan bir Uri hack'i bulduk. Javascript tarafında, KendoUI JS kütüphanesini, oluşturulmuş Date() nesnelerini UTC olarak görünecek şekilde kaydırmak için yatık.

Ardından da diğer tarafı seri kaldırma üzerinde çalışmaya başladı. Yine, kodumuzu, yerel saatten UTC'ye dönüştürüldüğünde verileri yeniden dengeleyen JSON.stringify yerine özel bir stringify kullanmak için ayarlamamız gerekiyordu. Her şey şimdiye kadar iyi görünüyordu.

Ama bu test bakmak:

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); 
    } 

Neden JavaScriptSerializer \/Date(286769410010)\/ UTC saat dizeleri ancak 1979-02-02T02:10:10Z yerel saate serisini geliyor?

Bizim özel JavascriptConverter bir Deserialize yöntemi eklemek çalıştı ama sorun Deserialize bizim JavascriptConverter aşağıdaki türden varsa denilen asla olmasıdır:

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

, Deserialize sadece SupportedTypes eğer aranmak DateTime alanlarına sahip bazı karmaşık varlıkların türlerini içerir.

Yani, JavaScriptSerializer ve JavascriptConverter iki tutarsızlıklar vardır:

  • serialize her veri öğesi için SupportedTypes dikkate basit türleri alır, ama Deserialize basit türleri için bunu yok sayar
  • Deserialize UTC ve bazı gibi bazı tarihleri ​​deserializes - yerel saat olarak.

Bu sorunları düzeltmenin basit bir yolu var mı? Biz diğer bazı serileştiriciye ile JavaScriptSerializer yerine korkuyor biraz biz, JavaScriptSerializer bazı bazı "özellikler/böcek" üzerine güvenerek kullandığınız 3. parti kütüphanelerin belki bazı çünkü.

cevap

36

JavaScriptSerializer ve DataContractJsonSerializer hatalarla karıştırılmıştır. Bunun yerine json.net kullanın. Microsoft bile bu anahtarı ASP.Net MVC4'te ve diğer yeni projelerde yaptı.

/Date(286769410010)/ biçimi Microsoft'a aittir ve özel olarak hazırlanmıştır. Sorunları var ve yaygın olarak desteklenmiyor. Her yerde 1979-02-02T02:10:10Z biçimini kullanmalısınız. Bu, ISO8601 ve RF3339'da tanımlanmıştır. Bu hem makine hem de insan tarafından okunabilir, sözcüksel olarak sıralanabilir, kültür değişmez ve belirsizdir.Eğer yeni tarayıcılarda çalışan edilecektir garanti edemez eğer JavaScript'inizde

, ardından kullanın:

date.toISOString() 

Reference here.

Tam tarayıcı ve eski tarayıcı desteği istiyorsanız, bunun yerine moment.js kullanın.

GÜNCELLEME gerçekten JavaScriptSerializer kullanmaya devam etmek istiyorsanız kenara, doğru zaman koruyacak bir DateTimeOffset e serisini olabilecek bir olarak

.

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

Testiniz şimdi geçecek şu şekildedir: Daha sonra oradan UTC DateTime alabilir.

+1

Tamam - bu tüm iyi ve iyi ve yararlı, ama Msft için saçma mazeret sadece daha iyi json kütüphanesi nakliye ve buggy JavaScriptSerializer tek başına bırakarak değil ne? – nothingisnecessary