2

我的 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 层(因为我还需要在那里进行转换,用于数据网格),但“回复”始终等于“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 中,我需要更改代码。

我在其中一种方法中的时间转换代码有问题吗?

4

1 回答 1

1

如果我对您的理解正确,那么您的问题归结为ConvertTimeBySystemTimeZoneId和之间的区别ConvertTimeFromUtc

首先,您需要了解任何涉及的时区转换操作DateTime都可能存在行为差异,具体取决于您赋予它.Kind的值。DateTime当您查看每种方法的文档(此处此处)时,您会发现一个描述三种不同类型( 、 和 )中每一种的行为UtcLocal图表Unspecified

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

具体问题的实际原因是您可能传入了DateTimewho's .Kindis Unspecified。在ConvertTimeBySystemTimeZoneId方法中,它将被视为Local,而在ConvertTimeFromUtc方法中,它将被视为Utc

有两种解决方案。

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

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

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

    这会变成这样:

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

我假设你正在做一个直接的 ADO.Net 调用并有DataReader响应。相应地调整你实际在做什么。

于 2013-08-17T19:10:57.420 回答