正确获取或设置CrmDateTime中的日期和时间值
像MSCRM这样的全球性产品,使用时不可避免会遇到跨时区的问题,因此都会采取相应的措施。MSCRM利用FilteredView很好地处理了这个问题:在底层的数据库表中,MSCRM实际存储的是UTC时间,而相应的FilteredView则会有两个时间,一个是UTC时间,一个是本地时间。MSCRM在将日期时间返回到页面的时候,会返回这个本地时间。本地时间取决于不同的用户的个人设置,在[Tools]->[Options]->[General]上面会有一个Time Zone设置。更改这里的时区,将会影响到CRM页面上时间的显示。
作为编程和二次开发来讲,也会遇到这个时间问题。MSCRM Web Service返回的时间类型是CrmDateTime类型,CrmDateTime类型有一个关键属性:value。这个属性支持UTC时间格式和本地时间格式。MSCRM Web Service返回的CrmDateTime.value是形如“2014-04-30T00:00:00-08:00”的日期时间格式,也就是说,会附带时区偏移量。而.Net Framework中的System.DateTime采取这样格式的字符串初始化时,如不指定时区和格式,会自动将其转换成本地时间——这个本地时间,是.Net程序所在的本地时间,而不是MSCRM用户设置的本地时间。当这两个本地时间不处在同一个时区时,容易因为混淆而引起程序bug,下面将会举例。
假设MSCRM中其中一名用户将其Time Zone设置为西八区(GMT -08:00),而.Net程序部署所在的操作系统时区设置为东八区(GMT +08:00)。这个时候通过调用MSCRM Web Service获取的activeon时间为“2014-04-30T00:00:00-08:00”。转换成System.DateTime之后时间变成“2014-04-30 16:00:00”,时区是东八区。如果程序保存时,简单地将System.DateTime变量来一个ToString再赋值给CrmDateTime,则MSCRM将会把“2014-04-30 16:00:00”作为该用户设置的本地时间(西八区)进行保存。这样一进一出将导致时间上相差16个小时。
因此,比较稳妥的办法是,采用DateTime.Now.ToUniversalTime().ToString("u")将本地时间转换成UTC时间,并且在ToString的时候一定要带上UTC的格式。一句话,在保存日期和时间字段的时候,如果采用UTC时间,是最为稳妥的事情,这样时间不会出现错误的偏移。
查询的时候,也要注意输入的字符串如果不是UTC格式的话,将会以用户设置的Time Zone当地时间进行查询——这样可能导致查不到准确的结果。