Наш клиент хотел, чтобы значения даты и времени отображались в браузере точно так же, как они находятся в базе данных, и мы сохраняем их как UTC в базе данных.
Сначала у нас были проблемы со стороной сериализации и Javascript. Значения DateTime были сдвинуты дважды - сначала в соответствии с местным часовым поясом компьютера, а затем в соответствии с часовым поясом в браузере. Мы исправили это, добавив специальный конвертер в JavaScriptSerializer. Мы отметили DateTime как DateTimeKind.Utc в переопределении Serialize. Было немного сложно передать данные обратно из Serialize, но мы нашли хак Uri, который помог вернуть значения DateTime в том же формате JavaScriptSerializer / Date (286769410010) /, но без перехода на местное время. На стороне Javascript мы исправили библиотеку KendoUI JS, чтобы компенсировать созданные объекты Date (), чтобы они выглядели так, как если бы они были в формате UTC.
Затем мы начали работать над другой стороной - десериализацией. Опять же, нам пришлось настроить наш код, чтобы использовать настраиваемый stringify вместо JSON.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 по местному времени?
Мы пытались добавить метод Deserialize к нашему пользовательскому JavascriptConverter, но проблема в том, что Deserialize никогда не вызывается, если наш JavascriptConverter имеет следующие типы:
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
Я предполагаю, что Deserialize будет вызываться только в том случае, если SupportedTypes содержит типы некоторых сложных сущностей, которые имеют поля DateTime.
Итак, JavaScriptSerializer и JavascriptConverter имеют два несоответствия:
- Serialize учитывает простые типы в SupportedTypes для каждого элемента данных, но Deserialize игнорирует его для простых типов.
- Deserialize десериализует некоторые даты как UTC, а некоторые - как местное время.
Есть ли простой способ исправить эти проблемы? Мы немного боимся заменять JavaScriptSerializer каким-либо другим сериализатором, потому что, возможно, некоторые из сторонних библиотек, которые мы используем, полагаются на некоторые определенные «особенности / ошибки» JavaScriptSerializer.