Advertisement
atsukanrock

Converting Invalid Local Time to UTC

Oct 25th, 2013
176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.21 KB | None | 0 0
  1. public static class TimeZoneConverter
  2. {
  3.     public static DateTime ToUtc(DateTime dateTime, TimeZoneInfo timeZone)
  4.     {
  5.         Guard.ArgumentNotNull(timeZone, "timeZone");
  6.  
  7.         if(!timeZone.IsInvalidTime(dateTime))
  8.         {
  9.             return TimeZoneInfo.ConvertTimeToUtc(dateTime, timeZone);
  10.         }
  11.  
  12.         // Find an adjustment rule to apply.
  13.         // An adjustment rule should be found because the localDateTime is invalid.
  14.         var date = dateTime.Date;
  15.         var adjustmentRule = timeZone.GetAdjustmentRules().FirstOrDefault(ar => ar.DateStart <= date && ar.DateEnd >= date);
  16.  
  17.         // Can be assumed because the localDateTime is invalid.
  18.         Debug.Assert(adjustmentRule != null, "condition: adjustmentRule != null");
  19.         Debug.Assert(adjustmentRule.DaylightDelta != TimeSpan.Zero,
  20.                      "condition: adjustmentRule.DaylightDelta != TimeSpan.Zero");
  21.  
  22.         // If clocks are turned forward during DST, invalid time occurs at the start of DST;
  23.         // otherwise, it occurs at the end of DST.
  24.         var transitionTime = adjustmentRule.DaylightDelta > TimeSpan.Zero
  25.                                  ? adjustmentRule.DaylightTransitionStart
  26.                                  : adjustmentRule.DaylightTransitionEnd;
  27.  
  28.         var transitionDateTime = CalculateTransitionDateTime(dateTime.Year, transitionTime);
  29.         if(transitionDateTime > dateTime)
  30.         {
  31.             // The invalid time crosses year.
  32.             // No system time zone applies to this as of 2013/08/28.
  33.             transitionDateTime = CalculateTransitionDateTime(dateTime.Year - 1, transitionTime);
  34.         }
  35.         Debug.Assert(transitionDateTime <= dateTime, "condition: transitionDateTime <= dateTime");
  36.  
  37.         var nextValidDateTime = adjustmentRule.DaylightDelta > TimeSpan.Zero
  38.                                     ? transitionDateTime.Add(adjustmentRule.DaylightDelta)
  39.                                     : transitionDateTime.Add(-adjustmentRule.DaylightDelta);
  40.         Debug.Assert(nextValidDateTime > dateTime, "condition: nextValidDateTime > dateTime");
  41.         Debug.Assert(!timeZone.IsInvalidTime(nextValidDateTime), "condition: !timeZone.IsInvalidTime(nextValidDateTime)");
  42.  
  43.         return TimeZoneInfo.ConvertTimeToUtc(nextValidDateTime, timeZone);
  44.     }
  45.  
  46.     public static DateTime CalculateTransitionDateTime(int year, TimeZoneInfo.TransitionTime transitionTime)
  47.     {
  48.         var timeOfDay = transitionTime.TimeOfDay;
  49.         if(transitionTime.IsFixedDateRule)
  50.         {
  51.             // If transitionTime.Month is 2 and transitionTime.Day 29,
  52.             // Feb. 28 should be returned depending on year.
  53.             var daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month);
  54.             return new DateTime(year, transitionTime.Month, ComparableUtils.Min(transitionTime.Day, daysInMonth),
  55.                                 timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
  56.         }
  57.  
  58.         Debug.Assert(1 <= transitionTime.Week && transitionTime.Week <= 5,
  59.                      "condition: 1 <= transitionTime.Week && transitionTime.Week <= 5");
  60.  
  61.         var result = new DateTime(year, transitionTime.Month, 1,
  62.                                   timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
  63.         var dayOfWeekDiff = (int)transitionTime.DayOfWeek - (int)result.DayOfWeek;
  64.         if(dayOfWeekDiff < 0)
  65.         {
  66.             dayOfWeekDiff += 7;
  67.         }
  68.         var dayDiff = (transitionTime.Week - 1) * 7 + dayOfWeekDiff;
  69.         if(dayDiff > 0)
  70.         {
  71.             result = result.AddDays(dayDiff);
  72.         }
  73.         Debug.Assert(result.DayOfWeek == transitionTime.DayOfWeek,
  74.                      "condition: result.DayOfWeek == transitionTime.DayOfWeek");
  75.         if(result.Month == transitionTime.Month)
  76.         {
  77.             return result;
  78.         }
  79.  
  80.         Debug.Assert(transitionTime.Week == 5, "condition: transitionTime.Week == 5");
  81.         Debug.Assert(result.Month == transitionTime.Month + 1, "condition: result.Month == transitionTime.Month + 1");
  82.         Debug.Assert(result.Day <= 7, "condition: result.Day <= 7");
  83.         // Week 5 means last week of the month.
  84.         return result.AddDays(-7);
  85.     }
  86. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement