我的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'。
我用Google搜索,并注意到我应该采用稍微不同的方式。所以我将我的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;
}
它有效!
我无法理解为什么它在我的数据层中有效,但在用户界面中,我需要更改代码。
我在其中一种方法中使用时间转换代码做错了吗?
答案 0 :(得分:1)
如果我理解正确,您的问题归结为ConvertTimeBySystemTimeZoneId
和ConvertTimeFromUtc
之间的区别。
首先,您需要了解任何涉及DateTime
的时区转换操作可能会产生行为差异,具体取决于您提供的.Kind
DateTime
的值。当您查看每个方法(here和here)的文档时,您会找到一个图表,描述三种不同类型(Utc
,{{ 1}}和Local
)。
这是.Net中的痛点,这就是为什么像Noda Time这样的库存在的原因。您可以在这两篇文章中阅读更多内容:
特定问题的实际原因是您可能传递的Unspecified
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调用。根据您的实际情况进行相应调整。