关于wcf:.NET 3.5中DateTime序列化的最佳做法

关于wcf:.NET 3.5中DateTime序列化的最佳做法

Best practices for DateTime serialization in .NET 3.5

大约4年前,我按照这篇MSDN文章介绍了DateTime使用的最佳实践,该最佳实践是在.Net 1.1和ASMX Web服务(以SQL 2000服务器为后端)上构建.Net客户端的。 我仍然记得DateTime遇到的序列化问题,以及它在不同时区中对服务器所做的测试工作。

我的问题是:是否为WCF和SQL Server 2008等某些新技术提供了类似的最佳实践文档,尤其是添加了新的datetime类型来存储时区感知信息。

这是环境:

  • 太平洋时间的SQL Server 2008。
  • Web Services层位于其他时区。
  • 客户端可能在不同时区使用.Net 2.0或.Net 3.5。 如果这很容易,我们可以强迫所有人升级到.Net 3.5。:)
  • 有关在每一层中使用的数据类型的任何好的建议/最佳实践?


    我认为最好的方法是始终将对象作为UTC传递,并在客户端上转换为本地时间。这样,所有客户都有一个共同的参考点。

    若要转换为UTC,请在DateTime对象上调用ToUniversalTime。然后,在客户端上,调用ToLocalTime以获取其当前时区。


    一个大问题是WCF序列化不支持xs:Date。这是一个很大的问题,好像您只需要一个日期,就不应该让您担心时区。以下连接问题讨论了一些问题:http://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=349215

    如果要明确表示一个时间点,即不仅仅是日期部分,则如果客户端和服务器上都装有.NET 3.5,则可以使用DateTimeOffset类。或为了实现互操作性,请始终将日期/时间值作为UTC传递。


    UTC / GMT在分布式环境中将保持一致。

    重要的一件事是在使用数据库中的值填充DateTime属性后,指定datetimeKind。

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

    参见MSDN


    只要您的Web服务层和客户端层使用.NET DateTime类型,它就应该正确地序列化和反序列化为带有时区信息的SOAP标准本地日期/时间,例如:

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

    如果绝对可以肯定地知道时区本身(即上面的时间可能是东部标准时间或中部夏令时),则需要创建自己的数据类型以将这些片段公开为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    [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;
        }
    }

    那么您的响应将如下所示:

    1
    2
    3
    <Now>2008-09-15T13:34:08.0039447-05:00</Now>
    <TimeZone>Central Daylight Time</TimeZone>
    <IsDaylightSavingTime>true</IsDaylightSavingTime>

    我很幸运,仅保留DateTime数据类型并将其始终存储为GMT。在每一层中,我都会将GMT值调整为该层的本地值。


    推荐阅读