.NET 3.5中DateTime序列化的最佳做法
大约4年前,我按照这篇MSDN文章介绍了DateTime使用最佳实践,该最佳实践是在.Net 1.1和ASMX Web服务(以SQL 2000服务器为后端)上构建.Net客户端的。我仍然记得DateTime遇到的序列化问题以及在不同时区的服务器所花费的测试工作。
我的问题是:是否为WCF和SQL Server 2008等某些新技术提供了类似的最佳实践文档,尤其是添加了新的datetime类型来存储时区感知信息。
这是环境:
- 太平洋时间的SQL Server 2008.
- Web服务层位于其他时区。
- 客户端可能在不同时区使用.Net 2.0或者.Net 3.5. 如果这很容易,我们可以强迫所有人升级到.Net 3.5. :)
有关在每个层中使用的数据类型的任何好的建议/最佳实践?
解决方案
回答
我认为最好的方法是始终将对象作为UTC传递,并在客户端上转换为本地时间。这样,所有客户都有一个共同的参考点。
若要转换为UTC,请在DateTime对象上调用ToUniversalTime。然后,在客户端上,调用ToLocalTime以获取其当前时区。
回答
我很幸运,只保留了DateTime数据类型并将其始终存储为GMT。在每一层中,我都会将GMT值调整为该层的本地值。
回答
只要Web服务层和客户端层使用.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>
回答
UTC / GMT在分布式环境中将保持一致。
重要的一件事是在使用数据库中的值填充DateTime属性后指定datetimeKind。
dateTimeValueUtcKind = DateTime.SpecifyKind(dateTimeValue, DateTimeKind.Utc);
参见MSDN
回答
一个大问题是WCF序列化不支持xs:Date。这是一个很大的问题,好像我们只需要一个日期,就不应该让我们担心时区。以下连接问题讨论了一些问题:http://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=349215
如果要明确表示一个时间点,即不仅仅是日期部分,则如果客户端和服务器上都装有.NET 3.5,则可以使用DateTimeOffset类。或者为了实现互操作性,请始终将日期/时间值作为UTC传递。