Operační systém Windows již několik verzí zpět obsahuje podporu pro změnu letního a standardního času. Pokud by jsme tedy ve své aplikaci potřebovali využít informace týkajících se změny na letní čas (daylight saving time – DST), je možné je získat přímo ze systému. To může být výhodné z toho důvodu, že pokud by došlo ke změně okamžiku, kdy se změna času provádí, Microsoft přes Windows Update vydá aktualizaci, která tuto případnou změnu zohlední a my se nemusíme o nic starat.
Informace o změně na letní čas jsou v systému vztažené k časové zóně. V .NETu jsou pak tyto informace pro libovolnou časovou zónu zpřístupněné od verze 3.5, kde je k dispozici nová třída TimeZoneInfo. Tato třída nám umožňuje získat změny času ve tvarů obecných pravidel (například, že ke změně na letní čas dochází pátou neděli v březnu).
Ukážeme si funkci, která získá kdy letní čas začíná, konči a dobu, o kterou se čas posouvá. Pro to bude potřeba provést převod nalezeného pravidla na konkrétní datum a čas. Vytvořená funkce bude mít jako vstupní parametr požadovaný rok a objekt TimeZoneInfo.
internal static class DaylightTimeUtil
{
#region action methods
public static DaylightTime GetDaylightTime(int year, TimeZoneInfo timeZone)
{
var rules = timeZone.GetAdjustmentRules();
if (rules.Length == 0) //No adjustment rules.
{
return null;
}
var rule = GetAdjustmentRule(rules, year);
if (rule == null) //No adjustment rules available for this year.
{
return null;
}
var startTransition = rule.DaylightTransitionStart;
int startYear = year;
var endTransition = rule.DaylightTransitionEnd;
int endYear = startYear;
//Does the transition back occur in an earlier month (i.e.,
//the following year) than the transition to DST? If so, make
//sure we have the right adjustment rule.
if (endTransition.Month < startTransition.Month)
{
endTransition = GetAdjustmentRule(rules, year + 1).DaylightTransitionEnd;
endYear++;
}
return new DaylightTime(TransitionTimeToDateTime(startYear, startTransition), TransitionTimeToDateTime(endYear, endTransition), rule.DaylightDelta);
}
#endregion
#region private member functions
private static TimeZoneInfo.AdjustmentRule GetAdjustmentRule(TimeZoneInfo.AdjustmentRule[] rules, int year)
{
//Iterate adjustment rules for time zone
foreach (TimeZoneInfo.AdjustmentRule rule in rules)
{
//Determine if this adjustment rule covers year desired
if (rule.DateStart.Year <= year && rule.DateEnd.Year >= year)
{
return rule;
}
}
return null;
}
private static DateTime TransitionTimeToDateTime(int year, TimeZoneInfo.TransitionTime transition)
{
DateTime timeOfDay = transition.TimeOfDay;
if (transition.IsFixedDateRule)
{
int daysInMonth = DateTime.DaysInMonth(year, transition.Month);
return new DateTime(year, transition.Month, daysInMonth < transition.Day ? daysInMonth : transition.Day, timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
}
DateTime dateTime;
if (transition.Week <= 4)
{
dateTime = new DateTime(year, transition.Month, 1, timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
int dayOfWeek = (int)dateTime.DayOfWeek;
int num = ((int)transition.DayOfWeek) - dayOfWeek;
if (num < 0)
{
num += 7;
}
num += 7 * (transition.Week - 1);
if (num > 0)
{
dateTime = dateTime.AddDays(num);
}
return dateTime;
}
int day = DateTime.DaysInMonth(year, transition.Month);
dateTime = new DateTime(year, transition.Month, day, timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
int num2 = (int)(dateTime.DayOfWeek - transition.DayOfWeek);
if (num2 < 0)
{
num2 += 7;
}
if (num2 > 0)
{
dateTime = dateTime.AddDays(-num2);
}
return dateTime;
}
#endregion
}
Použití vytvořené funkce může být pak následující:
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
Console.WriteLine("{0}:", timeZone.DaylightName);
var daylightTime = DaylightTimeUtil.GetDaylightTime(2012, timeZone);
if (daylightTime == null)
{
Console.WriteLine("No adjustment rules available.");
return;
}
Console.WriteLine("Start: {0:g}", daylightTime.Start);
Console.WriteLine("End: {0:g}", daylightTime.End);
Console.WriteLine("Delta: {0}", daylightTime.Delta);
Výstup z výše uvedeného kódu je následující:
Central Europe Daylight Time:
Start: 25. 3. 2012 2:00
End: 28. 10. 2012 3:00
Delta: 01:00:00