79182400

Date: 2024-11-12 19:04:56
Score: 0.5
Natty:
Report link

I credit most of the logic for this solution to @codtex and @stritch000. I noticed that the solution from @stritch000 uses the same adjustment rule for both the current and next year lookups, which might produce incorrect results if the adjustments change after the first year.

Here is an updated solution that addresses the next-year lookup while also preserving the southern hemisphere fix. It also uses Linq. If you plan to run this for many dates, you could cache the results of the Linq query for a given year/timezone in a dictionary

public static DateTime? GetNextTransition(DateTime asOfTime, TimeZoneInfo timeZone)
{
    var getAdjs = from adj in timeZone.GetAdjustmentRules()
                  from yr in (int[])[asOfTime.Year, asOfTime.Year + 1]
                  from t in (TimeZoneInfo.TransitionTime[])[adj.DaylightTransitionStart, adj.DaylightTransitionEnd]
                  where adj.DateStart.Year <= yr && adj.DateEnd.Year >= yr
                  select GetAdjustmentDate(t, yr);

    if (getAdjs.Where(a => a > asOfTime).Any())
    {
        return getAdjs.Where(a => a > asOfTime).Min();
    }
    return null;
}
public static System.Globalization.Calendar cal = System.Globalization.CultureInfo.CurrentCulture.Calendar;
public static DateTime GetAdjustmentDate(TimeZoneInfo.TransitionTime transitionTime, int year)
{
    if (!transitionTime.IsFixedDateRule)
    {
        int minDate = transitionTime.Week * 7 - 6; //1, 8, 15 ... This is the earliest date that works for transition.
        var minDateDayOfWeek = cal.GetDayOfWeek(new DateTime(year, transitionTime.Month, 1)); //the day for minDate
        int dayDiff = (transitionTime.DayOfWeek - minDateDayOfWeek + 7) % 7;
        int transitionDay = minDate + dayDiff;
        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);
    }
    else
    {
        return new DateTime(year, transitionTime.Month, transitionTime.Day);
    }
}
Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @codtex
  • User mentioned (0): @stritch000
  • User mentioned (0): @stritch000
  • Low reputation (1):
Posted by: ericcan