【问题标题】:Get the next date/time at which a daylight savings time transition occurs获取发生夏令时转换的下一个日期/时间
【发布时间】:2011-06-13 11:29:57
【问题描述】:

我想在 C# 中编写(或使用如果它已经退出)一个函数,它返回给定 System.TimeZoneInfo 对象和该时区中特定“截至”时间的下一个 DST 转换的日期/时间。返回的时间应在提供的时区中。我想要的函数有这个签名:

public DateTime GetNextTransition(DateTime asOfTime, TimeZoneInfo timeZone)
{
    // Implement me!
}

例如,如果我传入“东部标准时间”TimeZoneInfo 对象,并将 1/21/2011@17:00 作为“asOfTime”,我希望此函数返回 3/13/2011@2:00 .

System.TimeZoneInfo.TransitionTime 结构似乎包含我需要的所有信息,但理想情况下会有某种内置机制将规则转换为实际日期。有人有什么建议吗?

【问题讨论】:

  • 夏令时是一种相当动物......请记住,亚利桑那州的大部分地区(一些印度保留地尊重夏令时)不尊重夏令时。我们的时区仍然是 MST,因此我们不会调整我们的时间......而说丹佛将过渡到 MDT 并调整他们的时间。
  • 使用 Noda Time 并查看 this thread 了解如何使用它来获取转换时间。

标签: c# datetime dst


【解决方案1】:

看看这个页面上的例子,我想它会得到你需要的。

MSDN - TransitionTime

【讨论】:

  • 谢谢——我在这里发帖后不久也发现了这一点。我能够调整那里的代码来完成工作。一旦我对它更有信心,我会在我的问题中发布我的最终代码。框架没有公开浮动日期规则到实际日期的转换,这太糟糕了。
  • @StuartLange 在过去的 4.5 年里,我每一分钟都在这里,等待您发布您的代码。还在努力吗?
  • 请注意,有一个名为TransitionTimeToDateTime 的内部方法可以执行此操作。你可以找到它in the .NET Reference Source
  • @MattJohnson 仍然需要自己构建TransitionTime。这并不能解决OT发布的问题,我也在寻找解决方案......
  • @Azimuth - 查看TimeZoneInfo.GetAdjustmentRules。从那里开始很容易。但是,如果您想要更简单、更可靠的方法,请使用Noda Time
【解决方案2】:

你好_那里。可能为时已晚,但我会在这里发布我用于此目的的代码。这可能会确保某人有时间实施它。我实际上是在链接的帮助下做到的,这是@Jamiegs 的答案。

    public static DateTime? GetNextTransition(DateTime asOfTime, TimeZoneInfo timeZone)
    {
        TimeZoneInfo.AdjustmentRule[] adjustments = timeZone.GetAdjustmentRules();
        if (adjustments.Length == 0)
        {
            // if no adjustment then no transition date exists
            return null;
        }

        int year = asOfTime.Year;
        TimeZoneInfo.AdjustmentRule adjustment = null;
        foreach (TimeZoneInfo.AdjustmentRule adj in adjustments)
        {
            // Determine if this adjustment rule covers year desired
            if (adj.DateStart.Year <= year && adj.DateEnd.Year >= year)
            {
                adjustment = adj;
                break;
            }
        }

        if (adjustment == null)
        {
            // no adjustment found so no transition date exists in the range
            return null;
        }


        DateTime dtAdjustmentStart = GetAdjustmentDate(adjustment.DaylightTransitionStart, year);
        DateTime dtAdjustmentEnd = GetAdjustmentDate(adjustment.DaylightTransitionEnd, year);


        if (dtAdjustmentStart >= asOfTime)
        {
            // if adjusment start date is greater than asOfTime date then this should be the next transition date
            return dtAdjustmentStart;
        }
        else if (dtAdjustmentEnd >= asOfTime)
        {
            // otherwise adjustment end date should be the next transition date
            return dtAdjustmentEnd;
        }
        else
        {
            // then it should be the next year's DaylightTransitionStart

            year++;
            foreach (TimeZoneInfo.AdjustmentRule adj in adjustments)
            {
                // Determine if this adjustment rule covers year desired
                if (adj.DateStart.Year <= year && adj.DateEnd.Year >= year)
                {
                    adjustment = adj;
                    break;
                }
            }

            dtAdjustmentStart = GetAdjustmentDate(adjustment.DaylightTransitionStart, year);
            return dtAdjustmentStart;
        }
    }


    public static DateTime GetAdjustmentDate(TimeZoneInfo.TransitionTime transitionTime, int year)
    {
        if (transitionTime.IsFixedDateRule)
        {
            return new DateTime(year, transitionTime.Month, transitionTime.Day);
        }
        else
        {
            // For non-fixed date rules, get local calendar
            Calendar cal = CultureInfo.CurrentCulture.Calendar;
            // Get first day of week for transition
            // For example, the 3rd week starts no earlier than the 15th of the month
            int startOfWeek = transitionTime.Week * 7 - 6;
            // What day of the week does the month start on?
            int firstDayOfWeek = (int)cal.GetDayOfWeek(new DateTime(year, transitionTime.Month, 1));
            // Determine how much start date has to be adjusted
            int transitionDay;
            int changeDayOfWeek = (int)transitionTime.DayOfWeek;

            if (firstDayOfWeek <= changeDayOfWeek)
                transitionDay = startOfWeek + (changeDayOfWeek - firstDayOfWeek);
            else
                transitionDay = startOfWeek + (7 - firstDayOfWeek + changeDayOfWeek);

            // Adjust for months with no fifth week
            if (transitionDay > cal.GetDaysInMonth(year, transitionTime.Month))
                transitionDay -= 7;

            return new DateTime(year, transitionTime.Month, transitionDay, transitionTime.TimeOfDay.Hour, transitionTime.TimeOfDay.Minute, transitionTime.TimeOfDay.Second);
        }
    }

示例用法如下所示:

// This should give you DateTime object for date 26 March 2017 
// because this date is first transition date after 1 January 2017 for Central Europe Standard Time zone
DateTime nextTransitionDate = GetNextTransition(new DateTime(2017, 1, 1), TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time"))

你可以找到我用here玩过的代码。

【讨论】:

    【解决方案3】:

    System.TimeZoneInfo.TransitionTime 看起来像一个可以保存此类时间转换数据的结构,而不是一个计算实际值的函数。要创建这样的函数,我会在某处在线查找数据,然后使用静态 CreateFloatingDateRule 或 CreateFixedDateRule 方法创建值。

    【讨论】:

      猜你喜欢
      • 2017-08-28
      • 2010-10-15
      • 1970-01-01
      • 2010-11-29
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多