我的UI层中有一些代码,它应该采用UTC格式的DateTime,并将其转换为本地日期时间:
在我的数据层中,我只需执行以下操作:
private DateTime ConvertToLocal(DateTime dt)
{
if (_currentTimeZoneUser == string.Empty)
{
var u = new UserData(_userId).GetUser(_userId);
_currentTimeZoneUser = u.TimeZoneId;
}
var reply = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dt, _currentTimeZoneUser);
return reply;
}
其作用是检查是否设置了_currentTimeZoneUser。如果没有,请从用户表中获取zimezone,然后进行转换。
这个代码正在工作,我得到了一个有效的结果。
然后,我将代码复制到我的UI层(对于数据网格,我也需要在那里进行转换),但"reply"始终等于"dt"。
我在谷歌上搜索了一下,发现我应该用一种稍微不同的方式来做。所以我把我的UI方法改为:
public static DateTime GetLocalDateTime(DateTime serverTime)
{
var timeZoneId = HttpContext.Current.Session["TimeZoneId"].ToString();
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var reply = TimeZoneInfo.ConvertTimeFromUtc(serverTime, cstZone);
return reply;
}
它起作用了!
我不明白为什么它在我的数据层中有效,但在UI中,我需要更改代码。
在其中一个方法中,我的时间转换代码是否出错?
如果我理解正确,你的问题可以归结为ConvertTimeBySystemTimeZoneId
和ConvertTimeFromUtc
之间的区别。
首先,您需要了解,任何涉及DateTime
的时区转换操作都可能存在行为差异,这取决于您给它的DateTime
的.Kind
的值。当您查看这些方法中的每种方法的文档(此处和此处)时,您会发现一张图表,描述了三种不同类型(Utc
、Local
和Unspecified
)中每种的行为。
这是.Net的一个痛点,这就是像Noda Time这样的库存在的原因。你可以在这两篇文章中阅读更多:
- DateTime怎么了
- 起诉DateTime.Now
出现特定问题的实际原因是,您可能传入了一个DateTime
,其.Kind
就是Unspecified
。在ConvertTimeBySystemTimeZoneId
方法中,这将被视为Local
,而在ConvertTimeFromUtc
方法中,它将被视作为Utc
。
有两种解决方案。
-
第一个是您已经找到的——使用
ConvertTimeFromUtc
方法。您也应该在服务器代码中执行此操作。 -
第二种解决方案是在从数据库加载值时将
.Kind
设置为Utc
。在某个地方,你可能有这样的代码:foo.MyDateTime = (DateTime) dataReader["MyDateTime"]
这将改为:
foo.MyDateTime = DateTime.SpecifyKind( (DateTime) dataReader["MyDateTime"], DateTimeKind.Utc);
我假设您正在执行一个带有DataReader
响应的直接ADO.Net调用。根据你实际在做的事情进行相应的调整。