WCF-存储和还原UTC日期时间

时间:2018-07-02 10:12:42

标签: c# .net sql-server wcf datetime

我们向客户提供WCF Web服务,允许他们将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日期时间:

<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”实际上是UTC时间的ISO 8601 DateTime标准的一部分。如果在时间结束时加上“ Z”(祖鲁语),则表示该时间为UTC,因此真正的Z是时间的一部分

我怎么可能在读取方法的输出处使用Z?我是否需要修改存储在SQL Server中的数据类型?对服务的WSDL有影响吗?

2 个答案:

答案 0 :(得分:1)

无论何时需要保持时间偏移,都应使用DateTimeOffset(.netSqlServer

在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>

答案 1 :(得分:1)

Microsoft有explanation的说明如何将日期和时间与字符串转换为日期和时间;而您的问题(我将在下面介绍)是您丢失了Kind

DateTime ToString方法的“ o” standard format将为您提供所需的“往返”类型。

使用DateTime中的RoundTripKind Parse() with DateTimeStyles读回值。

您的DateTime缺少“ Z”指示符这一事实意味着(如在“ o”的“标准格式”页面上所记录的)DateTime的{​​{1}}是{{ 1}}。如果您已经从数据库中读取了这些Kind,则Unspecified将是DateTime(在读取Kind属性以确认后,您可以使用调试器对其进行检查这个)。

解决方法是,您必须知道要存储的Unspecified种类,因此可以在阅读时设置种类(因为如果不这样做,则种类将会是未指定)。例如,如果您仅存储Kind DateTime UTC,那么当您从数据库中读取它们时,可以在DateTime上适当地设置Kind。您可以这样做:

DateTime

我有一个扩展方法可以将其封装起来,所以我可以简单地调用:

Kind

通过以下方式实现:

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

或者您可以查看this answer来了解如何使用实体框架。

(请注意,这种方法适用于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); } } 。它们存储了DateTime和Offset,并确保您无需放入任何内容即可收回放入的内容。