Problemas de Datetime de JavaScriptSerializer UTC

Nuestro cliente quería mostrar los valores de fecha y hora en el navegador exactamente como están en la base de datos, y los almacenamos como UTC en la base de datos.

Al principio tuvimos algunos problemas con la serialización y el lado de Javascript. Los valores de DateTime se cambiaron dos veces: primero para que coincida con la zona horaria local de la máquina y luego para que coincida con la zona horaria en el navegador. Lo solucionamos agregando un convertidor personalizado al JavaScriptSerializer. Marcamos el DateTime para ser de DateTimeKind.Utc en la anulación de serialización. Fue un poco difícil devolver los datos de Serialize, pero encontramos algún truco de Uri que ayudó a devolver los valores de DateTime en el mismo formato JavaScriptSerializer / Date (286769410010) / pero sin cambiar a la hora local. En el lado de Javascript, hemos aplicado un parche a la biblioteca KendoUI JS para compensar los objetos Date () construidos de modo que aparezcan como UTC.

Luego comenzamos a trabajar en el otro lado, la deserialización. Una vez más, tuvimos que ajustar nuestro código para usar un stringify personalizado en lugar de JSON.stringify, que nuevamente compensa los datos al convertir de la hora local a UTC. Todo parecía bueno hasta ahora.

Pero mira esta prueba:

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

¿Por qué JavaScriptSerializer deserializa \/Date(286769410010)\/ cadenas a la hora UTC, pero 1979-02-02T02:10:10Z a la hora local?

Intentamos agregar un método Deserialize a nuestro JavascriptConverter personalizado, pero el problema es que nunca se llama a Deserialize si nuestro JavascriptConverter tiene los siguientes tipos:

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

Supongo que se llamaría Deserialize solo si SupportedTypes contiene tipos de algunas entidades complejas que tienen campos DateTime.

Entonces, JavaScriptSerializer y JavascriptConverter tienen dos inconsistencias:

  • Serialize tiene en cuenta tipos simples en SupportedTypes para cada elemento de datos, pero Deserialize lo ignora para los tipos simples
  • La deserialización deserializa algunas fechas como UTC y algunas como la hora local.

¿Hay alguna manera simple de solucionar estos problemas? Tenemos un poco de miedo de reemplazar JavaScriptSerializer con algún otro serializador porque tal vez algunas de las bibliotecas de terceros que estamos utilizando dependen de ciertas “características / errores” de JavaScriptSerializer .

JavaScriptSerializer y DataContractJsonSerializer están plagados de errores. Use json.net en su lugar. Incluso Microsoft ha hecho este cambio en ASP.Net MVC4 y otros proyectos recientes.

El formato /Date(286769410010)/ es propiedad e integrado por Microsoft. Tiene problemas y no es ampliamente compatible. Debe usar el formato 1979-02-02T02:10:10Z todas partes. Esto se define en ISO8601 y RF3339 . Es tanto legible por máquina como por humanos, léxico lisable, invariante de cultura y no ambiguo.

En JavaScript, si puede garantizar que se ejecutará en los navegadores más nuevos, use:

 date.toISOString() 

Referencia aquí .

Si desea una compatibilidad completa entre navegadores y navegadores anteriores, utilice moment.js en su lugar.

ACTUALIZAR

Como comentario aparte, si realmente quieres seguir usando JavaScriptSerializer , puedes deserializar a DateTimeOffset , lo que preservaría la hora correcta. A continuación, puede obtener el UTC DateTime desde allí, de la siguiente manera:

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

Tu prueba ahora pasará