JavaScriptSerializer UTC DateTime вопросы
наш клиент хотел показать значения даты и времени в браузере точно так же, как они находятся в базе данных, и мы храним их как UTC в базе данных.
сначала у нас были проблемы с сериализацией и Javascript. Значения DateTime были сдвинуты дважды-сначала в соответствии с локальным часовым поясом машины, а затем в соответствии с часовым поясом в браузере. Мы исправили это, добавив пользовательский конвертер в JavaScriptSerializer. Мы отметили DateTime, чтобы быть из значение datetimekind.Utc в переопределении сериализации. Было немного сложно вернуть данные из сериализации, но мы нашли некоторый взлом 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
по местному времени?
мы попытались добавить метод десериализации в наш пользовательский JavascriptConverter
но проблема в том, что десериализация никогда не вызывается, если наш JavascriptConverter имеет следующие типы:
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
Я думаю, десериализация будет называться, только если SupportedTypes
содержит типы некоторых сложных объектов, которые имеют поля DateTime.
и JavaScriptSerializer
и JavascriptConverter
есть две нестыковки:
- сериализация учитывает простые типы В SupportedTypes для каждого элемента данных, но десериализация игнорирует его для простых типов
- десериализация десериализует некоторые даты как UTC, а некоторые-как местное время.
есть ли простой способ исправить эти проблемы?
Мы немного боимся заменить JavaScriptSerializer
С некоторым другим сериализатором, потому что, возможно, некоторые из сторонних библиотек, которые мы используем, полагаются на некоторые определенные "функции/ошибки"JavaScriptSerializer
.
1 ответов
JavaScriptSerializer
и DataContractJsonSerializer
пронизаны ошибками. Используйте json.net вместо. Даже Microsoft сделала этот переключатель в ASP.Net MVC4 и другие недавние проекты.
на /Date(286769410010)/
формат является собственностью и составлен Microsoft. Она имеет проблемы и не пользуется широкой поддержкой. Вы должны использовать везде. Это определено в в формате iso8601 и RF3339. Это и машина и человек читаемый, лексически сортируемый, культура инвариантный и однозначный.
в JavaScript, если вы можете гарантировать, что будете работать в новых браузерах, используйте:
date.toISOString()
если вы хотите полный кросс-браузер и старше-поддержка браузера, используйте момент.js.
обновление
в сторону, если вы действительно хотите продолжать использовать JavaScriptSerializer
, вы можете десериализоваться в DateTimeOffset
, который сохранил бы правильное время. Затем вы можете получить UTC DateTime
оттуда, следующим образом:
// 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;
ваш тест сейчас пройду.