Monday, April 12, 2010

Daylight Savings Notice


Our office does not observe Daylight Savings. I wanted to display a notice on our order form to make users aware when daylight savings was changing. After spending hours not finding a way, I found code here . I added a method to it adapted from his code. I just wanted the dates daylight saving start and ends for a given TimeZone. I had already tried:

DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Today.Year);

But that only gives it for the time zone of the server. I needed to get a System.Globalization.DaylightTime for a timezone that observes Daylight Saving.

public static DaylightTime GetDaylightChanges(TimeZoneInfo InTimeZoneInfo, int InYear)
  {
   TimeZoneInfo.AdjustmentRule ruleFound = null;


   TimeZoneInfo.AdjustmentRule[] adjustments = InTimeZoneInfo.GetAdjustmentRules();
   if (adjustments.Length == 0)
   {
    throw new Exception(InTimeZoneInfo.StandardName + " has no adjustment rules");
   }
   //Find the correct adjustment rule
   foreach (TimeZoneInfo.AdjustmentRule adjustment in adjustments)
   {
    if (adjustment.DateStart.Year <= InYear && adjustment.DateEnd.Year >= InYear)
     ruleFound = adjustment;
   }
   if (ruleFound == null)
   {
    throw new Exception("No TimeZoneInfo.AdjustmentRule found for TimeZoneInfo "
     + InTimeZoneInfo.StandardName +" for year " + InYear);
   }


   DaylightTime outDaylightTime = new DaylightTime(
      GetDateTime(InYear, ruleFound.DaylightTransitionStart)
     , GetDateTime(InYear, ruleFound.DaylightTransitionEnd)
     , ruleFound.DaylightDelta);


   return outDaylightTime;
  }



public static DateTime GetDateTime(int Year, TimeZoneInfo.TransitionTime transactionTime)
{
//Create a datetime to begin with 1st of the transition month
DateTime dt = new DateTime(Year, transactionTime.Month,
1, transactionTime.TimeOfDay.Hour,
transactionTime.TimeOfDay.Minute, transactionTime.TimeOfDay.Second);


//If the dayofweek of 1st is same as the transition day then exit
//otherwise 
if (dt.DayOfWeek != transactionTime.DayOfWeek)
{
//If transition dayofweek is greater than 1st dayofweek then we need to move further
//Eg : Transition dayofweek is tuesday and 1st day of week is monday then we need to move 1 day ahead to point to 
//the transition day
if (dt.DayOfWeek < transactionTime.DayOfWeek)
{
dt.AddDays(transactionTime.DayOfWeek - dt.DayOfWeek);
}
else
{
//else its not in the 1st week so we move 7 days ahead and move back again
dt = dt.AddDays(7 - (dt.DayOfWeek - transactionTime.DayOfWeek));
}
}


//Since we are already pointing to the first week of the transition date
//Add remaining no of weeks to the datetime
return dt.AddDays((transactionTime.Week - 1) * 7);
}


Here is the usage.

TimeZoneInfo PacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DaylightTime daylight = CustomTimeZone.GetDaylightChanges(PacificTimeZone, 2010);
Console.WriteLine("daylight.Start = " + daylight.Start);
Console.WriteLine("daylight.End = " + daylight.End);
Console.WriteLine("daylight.Delta = " + daylight.Delta);