WCF - Храните и восстанавливайте UTC DateTime - PullRequest
0 голосов
/ 02 июля 2018

Мы предоставляем нашим клиентам веб-сервис WCF, позволяющий им хранить DateTime в базах данных SQL Server. Выписка из WSDL:

<xs:complexType name="TimePeriod">
<xs:sequence>
    <xs:element minOccurs="0" name="endDateTime" nillable="true" type="xs:dateTime"/>
    <xs:element minOccurs="0" name="startDateTime" nillable="true" type="xs:dateTime"/>
</xs:sequence>

Например, мой клиент отправляет мне UTC Datetime:

<af:effectivePeriod>
   <af:startDateTime>2018-01-16T10:32:28Z</af:startDateTime>
</af:effectivePeriod>

Он хранится в базе данных SQL Server в поле datetime.

Но на выходе службы чтения у меня нет индикатора UTC:

<af:effectivePeriod>
   <af:startDateTime>2018-01-16T10:32:28</af:startDateTime>
</af:effectivePeriod>

«Z» является своего рода уникальным случаем для DateTimes. Буква «Z» фактически является частью стандарта ISO 8601 DateTime для времени UTC. Когда «Z» (Zulu) привязан к концу времени, это означает, что это время UTC, поэтому в действительности литерал Z является частью времени

Как я могу получить Z на выходе метода read? Нужно ли изменять тип данных, хранящихся в SQL Server? Имею ли я влияние на WSDL сервисов?

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

У Microsoft есть объяснение о том, как "обходить" даты и время при преобразовании их в и из строк; и ваша проблема (о которой я расскажу ниже) состоит в том, что вы потеряли Kind.

Метод DateTime ToString "o" стандартный формат даст вам вид "туда-обратно", который вы ищете.

Используйте DateTime Parse () с DateTimeStyles из RoundTripKind, чтобы прочитать значение обратно.

Тот факт, что в вашем DateTime отсутствует индикатор 'Z', означает (как указано на странице стандартного формата для "o"), что DateTime '* Kind равно Unspecified. Если вы прочитали эти DateTime s из своей базы данных, Kind будет Unspecified (вы можете использовать отладчик для проверки свойства Kind после его прочтения, чтобы подтвердить это).

Способ заключается в том, что вы должны знать, какие типы DateTime вы храните, чтобы вы могли установить Вид, когда читаете его (потому что, если вы этого не сделаете, Вид будет Неуказанным) , Например, если вы храните только UTC Kind DateTime с, то когда вы читаете их из своей базы данных, вы можете установить Kind в DateTime соответствующим образом. Вы можете сделать это так:

var myUtcDateTime = DateTime.SpecifyKind(myUnspecifiedDateTime, DateTimeKind.Utc);

У меня есть метод расширения для инкапсуляции этого от меня, поэтому я могу просто позвонить:

var myDateTime = dataReader.GetUtcDateTime(ordinal);

, который реализован так:

public static class DataReaderExtensions
{
    public static DateTime GetUtcDateTime(this IDataReader reader, int ordinal)
    {
        var readDateTime = reader.GetDateTime(ordinal);
        return DateTime.SpecifyKind(readDateTime, DateTimeKind.Utc);
    }
}

Или вы можете посмотреть этот ответ , чтобы узнать, как это сделать с помощью Entity Framework.

(Обратите внимание, что этот подход работает для UTC; но вы не можете решить сделать то же самое с типом Local, так как нет гарантии, что локальный код, в котором вы читаете значение, тот же самый в котором это было написано. Например, переход на летнее время, возможно, только начался или закончился.)

Но я должен сказать, что если вы действительно интересуетесь фактическим временем, лучшее решение этой разновидности проблемы (если вы простите за каламбур!) это используйте DateTimeOffset с. Они хранят DateTime и Offset и гарантируют, что вы вернете то, что положили, без необходимости возиться с вещами.

0 голосов
/ 02 июля 2018

Всякий раз, когда вам нужно сохранить смещение времени, вы должны работать с DateTimeOffset ( .net & SqlServer )

В свой объект WCF-данных вы можете добавить DateTimeOffset DataMember, однако это повлияет на клиентскую сторону, и ваш сервис wsdl изменится, так как будет создан сложный тип DateTimeOffset:

<xs:complexType name="DateTimeOffset">
    <xs:annotation>
        <xs:appinfo>
            <IsValueType>true</IsValueType>
        </xs:appinfo>
    </xs:annotation>
    <xs:sequence>
        <xs:element name="DateTime" type="xs:dateTime"/>
        <xs:element name="OffsetMinutes" type="xs:short"/>
    </xs:sequence>
</xs:complexType>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...