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;

ваш тест сейчас пройду.