TimeZoneInfo在两位代码中的工作方式不同

时间:2013-08-17 07:12:36

标签: c# timezone

我的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;
}

它有效!

我无法理解为什么它在我的数据层中有效,但在用户界面中,我需要更改代码。

我在其中一种方法中使用时间转换代码做错了吗?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您的问题归结为ConvertTimeBySystemTimeZoneIdConvertTimeFromUtc之间的区别。

首先,您需要了解任何涉及DateTime的时区转换操作可能会产生行为差异,具体取决于您提供的.Kind DateTime的值。当您查看每个方法(herehere)的文档时,您会找到一个图表,描述三种不同类型(Utc,{{ 1}}和Local)。

这是.Net中的痛点,这就是为什么像Noda Time这样的库存在的原因。您可以在这两篇文章中阅读更多内容:

特定问题的实际原因是您可能传递的Unspecified DateTime .KindUnspecified。在ConvertTimeBySystemTimeZoneId方法中,将其视为Local,而在ConvertTimeFromUtc方法中,它将被视为Utc

有两种解决方案。

  • 首先是您已经找到的内容 - 使用ConvertTimeFromUtc方法。您也应该在服务器代码中执行此操作。

  • 第二种解决方案是在从数据库加载值时将.Kind设置为Utc。某处你可能有这样的代码:

    foo.MyDateTime = (DateTime) dataReader["MyDateTime"]
    

    哪个会改变:

    foo.MyDateTime = DateTime.SpecifyKind(
                       (DateTime) dataReader["MyDateTime"],
                       DateTimeKind.Utc);
    

我假设您正在使用DataReader响应进行直接ADO.Net调用。根据您的实际情况进行相应调整。