Il nostro cliente voleva mostrare i valori di data e ora nel browser esattamente come sono nel database, e li stiamo memorizzando come UTC nel database.JavaScriptSerializer UTC DateTime problemi
All'inizio abbiamo avuto alcuni problemi con la serializzazione e il lato Javascript. I valori DateTime sono stati spostati due volte - all'inizio per abbinare il fuso orario locale della macchina e quindi per abbinare il fuso orario nel browser. L'abbiamo risolto aggiungendo un convertitore personalizzato a JavaScriptSerializer. Abbiamo contrassegnato il DateTime come DateTimeKind.Utc in Serialize override. È stato un po 'difficile alimentare i dati dal Serialize, ma abbiamo trovato alcuni Uri hack che hanno aiutato a restituire i valori DateTime nello stesso JavaScriptSerializer/Date (286769410010)/format ma senza passare all'ora locale. Sul lato Javascript abbiamo patchato la libreria JS KendoUI per bilanciare gli oggetti Date() costruiti in modo che appaiano come se fossero UTC.
Poi abbiamo iniziato a lavorare dall'altra parte, la deserializzazione. Ancora una volta, abbiamo dovuto modificare il nostro codice per utilizzare un stringify personalizzato anziché JSON.stringify, che compensa nuovamente i dati durante la conversione dall'ora locale a UTC. Tutto sembrava buono finora.
Ma guarda questo test:
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);
}
Perché JavaScriptSerializer deserializzare \/Date(286769410010)\/
stringhe ora UTC ma 1979-02-02T02:10:10Z
in ora locale?
abbiamo cercato di aggiungere un metodo Deserialize al nostro personalizzato JavascriptConverter
ma il problema è che la Deserialize non viene mai chiamato se il nostro JavascriptConverter ha i seguenti tipi:
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
immagino, Deserialize sarebbe chiamato solo se SupportedTypes
tipi contenuti di alcune entità complesse che hanno campi DateTime.
Così, JavaScriptSerializer
e JavascriptConverter
hanno due incongruenze:
- Serialize prende in considerazione i tipi semplici in SupportedTypes per ogni elemento di dati, ma Deserialize ignora per i tipi semplici
- Deserialize deserializza alcune date come UTC e un po ' - come ora locale.
C'è qualche modo semplice per risolvere questi problemi? Abbiamo un po 'paura di sostituire JavaScriptSerializer
con qualche altro serializzatore perché forse alcune delle librerie di terze parti che stiamo usando si affidano ad alcune "caratteristiche/bug" di JavaScriptSerializer
.
Ok, quindi tutto va bene, è utile e utile, ma qual è la scusa della cazzata per Msft, non solo per spedire la migliore libreria JSON e per lasciare solo il buggy JavaScriptSerializer? – nothingisnecessary