Лучшие практики сериализации DateTime в .NET 3.5

Примерно 4 года назад я следовал этой статье в MSDN, посвященной передовым методам использования DateTime. для создания клиента .Net на веб-сервисах .Net 1.1 и ASMX (с сервером SQL 2000 в качестве бэкэнда). Я до сих пор помню проблемы сериализации, которые у меня были с DateTime, и усилия по тестированию серверов в разных часовых поясах.

У меня такой вопрос: существует ли аналогичный документ с лучшими практиками для некоторых новых технологий, таких как WCF и SQL server 2008, особенно с добавлением новых типов datetime для хранения информации о часовом поясе.

Это среда:

  1. SQL server 2008 по тихоокеанскому времени.
  2. Слой веб-служб в другом часовом поясе.
  3. Клиенты могут использовать .Net 2.0 или .Net 3.5 в разных часовых поясах. Если это упростит задачу, мы можем заставить всех перейти на .Net 3.5. :)

Какие-нибудь хорошие предложения / лучшие практики для типов данных, которые будут использоваться на каждом уровне?


person Gulzar Nazim    schedule 15.09.2008    source источник


Ответы (6)


Я думаю, что лучший способ сделать это - всегда передавать объект как UTC и конвертировать в местное время на клиентах. Таким образом, все клиенты получают общую точку отсчета.

Чтобы преобразовать в UTC, вызовите ToUniversalTime для объекта DateTime. Затем на клиентах вызовите ToLocalTime, чтобы получить его в их текущем часовом поясе.

person Abe Heidebrecht    schedule 15.09.2008
comment
Обратите внимание, что клиент получит тип datetime как Unspecified. Когда вы вызываете ToUniversalTime на нем, он предполагает Local время и фактически выполняет преобразование. Правильный способ - использовать DateTime.SpecifyKind(myUtcTime, DateTimeKind.Utc) вместо ToUniversalTime. - person Eren Ersönmez; 06.08.2015

Одна большая проблема заключается в том, что сериализация WCF не поддерживает xs: Date. Это большая проблема, так как если все, что вам нужно, это свидание, вам не следует беспокоиться о часовых поясах. Следующая проблема подключения описывает некоторые из проблем: http://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=349215.

Если вы хотите однозначно представить момент времени, то есть не только дату, вы можете использовать класс DateTimeOffset, если у вас есть .NET 3.5 как на клиенте, так и на сервере. Или для обеспечения совместимости всегда передавайте значения даты и времени в формате UTC.

person Joe    schedule 16.09.2008
comment
Если вы хотите использовать DateTimeOffset и WCF, эти две статьи могут быть полезны при возникновении проблем с сериализацией: msdn.microsoft.com/en-us/library/ms730167 (v = VS.90) .aspx blogs.msdn.com/b/drnick/archive/2008/09/04 / - person Perhentian; 21.09.2011
comment
по состоянию на 28.03.2013 ссылка в посте Джо не работает. - person Zack Jannsen; 28.03.2013

UTC / GMT будет согласованным в распределенной среде.

Одна важная вещь заключается в том, что укажите datetimeKind после заполнения вашего свойства DateTime значением из базы данных.

dateTimeValueUtcKind = DateTime.SpecifyKind(dateTimeValue, DateTimeKind.Utc);

См. MSDN

person Ray Lu    schedule 16.09.2008

Пока ваш уровень веб-сервисов и уровень клиента используют тип .NET DateTime, он должен правильно сериализоваться и десериализоваться как стандартная локальная дата / время SOAP с информацией о часовом поясе, например:

2008-09-15T13:14:36.9502109-05:00

Если вы абсолютно точно должны знать сам часовой пояс (т.е.вышеупомянутое может быть восточное стандартное время или центральное летнее время), вам необходимо создать свой собственный тип данных, который представляет эти части как таковые:

[Serializable]
public sealed class MyDateTime
{
    public MyDateTime()
    {
        this.Now = DateTime.Now;
        this.IsDaylightSavingTime = this.Now.IsDaylightSavingTime();
        this.TimeZone = this.IsDaylightSavingTime
            ? System.TimeZone.CurrentTimeZone.DaylightName
            : System.TimeZone.CurrentTimeZone.StandardName;
    }

    public DateTime Now
    {
        get;

        set;
    }

    public string TimeZone
    {
        get;

        set;
    }

    public bool IsDaylightSavingTime
    {
        get;

        set;
    }
}

тогда ваш ответ будет выглядеть так:

<Now>2008-09-15T13:34:08.0039447-05:00</Now>
<TimeZone>Central Daylight Time</TimeZone>
<IsDaylightSavingTime>true</IsDaylightSavingTime>
person Jesse C. Slicer    schedule 15.09.2008
comment
Вот как теперь работает WCF. Я не получаю ничего с указанием часового пояса (например, -05: 00). - person Piotr Owsiak; 08.01.2010

Мне повезло, что я просто сохранил тип данных DateTime и всегда сохранял его как GMT. В каждом слое я бы настроил значение GMT ​​на локальное значение для слоя.

person Mark    schedule 15.09.2008

В случаях, когда объект datetime должен оставаться неизменным, используйте JsonConvert:

DateTime now = DateTime.Now;
string json = JsonConvert.SerializeObject(now);
DateTime nowJson = JsonConvert.DeserializeObject<DateTime>(json);
person Laobu    schedule 30.11.2020