Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static class TimeZoneConverter
- {
- public static DateTime ToUtc(DateTime dateTime, TimeZoneInfo timeZone)
- {
- Guard.ArgumentNotNull(timeZone, "timeZone");
- if(!timeZone.IsInvalidTime(dateTime))
- {
- return TimeZoneInfo.ConvertTimeToUtc(dateTime, timeZone);
- }
- // Find an adjustment rule to apply.
- // An adjustment rule should be found because the localDateTime is invalid.
- var date = dateTime.Date;
- var adjustmentRule = timeZone.GetAdjustmentRules().FirstOrDefault(ar => ar.DateStart <= date && ar.DateEnd >= date);
- // Can be assumed because the localDateTime is invalid.
- Debug.Assert(adjustmentRule != null, "condition: adjustmentRule != null");
- Debug.Assert(adjustmentRule.DaylightDelta != TimeSpan.Zero,
- "condition: adjustmentRule.DaylightDelta != TimeSpan.Zero");
- // If clocks are turned forward during DST, invalid time occurs at the start of DST;
- // otherwise, it occurs at the end of DST.
- var transitionTime = adjustmentRule.DaylightDelta > TimeSpan.Zero
- ? adjustmentRule.DaylightTransitionStart
- : adjustmentRule.DaylightTransitionEnd;
- var transitionDateTime = CalculateTransitionDateTime(dateTime.Year, transitionTime);
- if(transitionDateTime > dateTime)
- {
- // The invalid time crosses year.
- // No system time zone applies to this as of 2013/08/28.
- transitionDateTime = CalculateTransitionDateTime(dateTime.Year - 1, transitionTime);
- }
- Debug.Assert(transitionDateTime <= dateTime, "condition: transitionDateTime <= dateTime");
- var nextValidDateTime = adjustmentRule.DaylightDelta > TimeSpan.Zero
- ? transitionDateTime.Add(adjustmentRule.DaylightDelta)
- : transitionDateTime.Add(-adjustmentRule.DaylightDelta);
- Debug.Assert(nextValidDateTime > dateTime, "condition: nextValidDateTime > dateTime");
- Debug.Assert(!timeZone.IsInvalidTime(nextValidDateTime), "condition: !timeZone.IsInvalidTime(nextValidDateTime)");
- return TimeZoneInfo.ConvertTimeToUtc(nextValidDateTime, timeZone);
- }
- public static DateTime CalculateTransitionDateTime(int year, TimeZoneInfo.TransitionTime transitionTime)
- {
- var timeOfDay = transitionTime.TimeOfDay;
- if(transitionTime.IsFixedDateRule)
- {
- // If transitionTime.Month is 2 and transitionTime.Day 29,
- // Feb. 28 should be returned depending on year.
- var daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month);
- return new DateTime(year, transitionTime.Month, ComparableUtils.Min(transitionTime.Day, daysInMonth),
- timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
- }
- Debug.Assert(1 <= transitionTime.Week && transitionTime.Week <= 5,
- "condition: 1 <= transitionTime.Week && transitionTime.Week <= 5");
- var result = new DateTime(year, transitionTime.Month, 1,
- timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
- var dayOfWeekDiff = (int)transitionTime.DayOfWeek - (int)result.DayOfWeek;
- if(dayOfWeekDiff < 0)
- {
- dayOfWeekDiff += 7;
- }
- var dayDiff = (transitionTime.Week - 1) * 7 + dayOfWeekDiff;
- if(dayDiff > 0)
- {
- result = result.AddDays(dayDiff);
- }
- Debug.Assert(result.DayOfWeek == transitionTime.DayOfWeek,
- "condition: result.DayOfWeek == transitionTime.DayOfWeek");
- if(result.Month == transitionTime.Month)
- {
- return result;
- }
- Debug.Assert(transitionTime.Week == 5, "condition: transitionTime.Week == 5");
- Debug.Assert(result.Month == transitionTime.Month + 1, "condition: result.Month == transitionTime.Month + 1");
- Debug.Assert(result.Day <= 7, "condition: result.Day <= 7");
- // Week 5 means last week of the month.
- return result.AddDays(-7);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement