我已经看到许多网站(通常是论坛)允许用户通过选择以下内容来指定其TimeZone首选项:

  • 时区
  • 是否使用DST

  • 据我所知,.NET在进行转换时总是考虑DST,因此问题是:
    如何在C#中实现“不使用DST”部分?
    在这一点上,我介绍了到目前为止我能做的事情,但是感觉很棘手,我想知道是否有一种更清洁/更好的方法。
    首先,为确保自动应用DST,我编写了以下测试:

    [Test]
    public void DateTimeConversion_ToLocalTime_HandlesDSTByDefault()
    {
        var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
        var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);
    
        var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");
    
        Assert.AreEqual(3, TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone).Hour);
        Assert.AreEqual(2, TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone).Hour);
    }
    
    该测试通过,表明:
  • 当没有夏令时时(例如冬天),罗马尼亚时间为UTC + 2小时
  • (适用夏令时)(例如,夏季),罗马尼亚时间为UTC + 3小时
  • 进行DateTime转换时的
  • ,DST会自动考虑为

  • 接下来,我注意到 TimeZoneInfo.GetAdjustmentRules() 方法返回了 AdjustmentRule 对象数组,并且发现如果取消这些规则的效果,我可以获得DST不受影响的值。
    所以我写了下面的方法,如果DateTime对象is affected by DST做到了这一点:
    private DateTime RemoveDSTFromDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
    {
        if (!dateTime.IsDaylightSavingTime())
            return dateTime;
    
        var result = dateTime;
    
        foreach (var adjustmentRule in timeZoneInfo.GetAdjustmentRules())
            result = result.Subtract(adjustmentRule.DaylightDelta);
    
        return result;
    }
    
    回到原始DST/无DST方案,但是这次强制结果不受DST的影响:
    [Test]
    public void DateTimeConversion_ToLocalTime_WithoutDST()
    {
        var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
        var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);
    
        var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");
    
        var convertedDateWithDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone);
        var convertedDateWithoutDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone);
    
        Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithDst, roTimezone).Hour);
        Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithoutDst, roTimezone).Hour);
    }
    
    此测试也通过了,表明现在DST的效果已取消(无论一年中的什么时间,我们总是获得UTC + 2h)。
    在记下来的同时,我想到了另一个可行的想法:不用任何TimeZoneInfo.Convert...()方法,只需将roTimezone.BaseUtcOffset添加到UTC日期即可。
    任何人都可以指出执行此操作的正确方法吗?

    最佳答案

    解析您的问题,似乎您有两个建议的解决方案:

  • 确定DST调整并将其从转换后的输出中删除。
  • 取UTC的DateTime并添加BaseUtcOffset,以便您始终处理标准时间。

  • 由于您的问题是如何不实现DST,我想说您自己使用选项#2回答了它。

    就是说,您最初的假设是有缺陷的。许多站点要求提供时区和DST的原因通常是因为其时区实现一开始不支持DST。他们正在做的是让您选择一个基本偏移量,然后决定是否要在一年的设定时间内添加一个小时。他们可能将其称为“时区”,但它绝对不比.Net的TimeZoneInfo类或诸如Noda Time之类的库健壮。

    如果您确实是在选择“时区”(例如TimeZoneInfo.GetSystemTimeZones())(应保存Id属性并显示DisplayName属性),则绝对不应询问用户是否使用DST。如果用户居住在不使用DST的地方(例如在亚利桑那州),则已经有选择。用户通常会选择正确的选项来获得所需的效果,特别是如果他们居住在DST规则异常的地区(例如印第安纳州),则用户通常会非常擅长。

    如果您使用的是IANA/Olson风格的时区(例如"America/New York"),无论是Noda Time还是其他实现方式,都适用相同的想法。您应该将DST决定委托(delegate)给库-而不是用户。

    将其委托(delegate)给库的一个非常有效的论据是,这些DST规则可以更改,并且在其生命周期的许多点上都已更改。如果您正在编写处理过去信息的任何类型的应用程序或站点,则可能会发现今天有效的内容并不是对过去发生的内容的正确调整。另外,在时区世界中也有很多怪异之处,例如澳大利亚,其中某些地区的时间间隔是30分钟而不是一小时。您真的要自己管理吗?可能不会。 :)

    关于c# - 从DateTime删除DST,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12266948/

    10-13 06:22