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

本文关键字:工作 方式不 代码 两位 TimeZoneInfo | 更新日期: 2023-09-27 18:28:03

我的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中,我需要更改代码。

在其中一个方法中,我的时间转换代码是否出错?

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

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

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

这是.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调用。根据你实际在做的事情进行相应的调整。