TimeZoneInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / TimeZoneInfo.cs / 1305376 / TimeZoneInfo.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class: TimeZoneInfo 
**
** 
** Purpose:
** This class is used to represent a Dynamic TimeZone.  It
** has methods for converting a DateTime between TimeZones,
** and for reading TimeZone data from the Windows Registry 
**
** 
============================================================*/ 

/*=========================================================== 
**
** !!!!!!!!! READ ME IF YOU ARE FIXING A

 

 
 

 



 

*/ 
namespace System { 
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles; 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel; 
    using System.Diagnostics;
    using System.Diagnostics.Contracts; 
    using System.Globalization; 
    using System.IO;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Runtime.Versioning;
    using System.Security; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading; 

    // 
    // DateTime uses TimeZoneInfo under the hood for IsDaylightSavingTime, IsAmbiguousTime, and GetUtcOffset.
    // These TimeZoneInfo APIs can throw ArgumentException when an Invalid-Time is passed in.  To avoid this
    // unwanted behavior in DateTime public APIs, DateTime internally passes the
    // TimeZoneInfoOptions.NoThrowOnInvalidTime flag to internal TimeZoneInfo APIs. 
    //
    // In the future we can consider exposing similar options on the public TimeZoneInfo APIs if there is enough 
    // demand for this alternate behavior. 
    //
    [Flags] 
    internal enum TimeZoneInfoOptions {
        None                      = 1,
        NoThrowOnInvalidTime      = 2
    }; 

 
    [Serializable] 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 
    sealed public class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback {

        // ---- SECTION:  members supporting exposed properties -------------*
        private String m_id; 
        private String m_displayName;
        private String m_standardDisplayName; 
        private String m_daylightDisplayName; 
        private TimeSpan m_baseUtcOffset;
        private Boolean m_supportsDaylightSavingTime; 
        private AdjustmentRule[] m_adjustmentRules;

        // ---- SECTION:  members for internal support ---------*
        private enum TimeZoneInfoResult { 
            Success                   = 0,
            TimeZoneNotFoundException = 1, 
            InvalidTimeZoneException  = 2, 
            SecurityException         = 3
        }; 


#if FEATURE_WIN32_REGISTRY
        // registry constants for the 'Time Zones' hive 
        //
        private const string c_timeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; 
        private const string c_timeZonesRegistryHivePermissionList = @"HKEY_LOCAL_MACHINE\" + c_timeZonesRegistryHive; 
        private const string c_displayValue = "Display";
        private const string c_daylightValue = "Dlt"; 
        private const string c_standardValue = "Std";
        private const string c_muiDisplayValue = "MUI_Display";
        private const string c_muiDaylightValue = "MUI_Dlt";
        private const string c_muiStandardValue = "MUI_Std"; 
        private const string c_timeZoneInfoValue = "TZI";
        private const string c_firstEntryValue = "FirstEntry"; 
        private const string c_lastEntryValue = "LastEntry"; 

        // registry constants for the 'TimeZoneInformation' hive 
        //
        private const string c_timeZoneInfoRegistryHive = @"SYSTEM\CurrentControlSet\Control\TimeZoneInformation";
        private const string c_timeZoneInfoRegistryHivePermissionList = @"HKEY_LOCAL_MACHINE\" + c_timeZoneInfoRegistryHive;
        private const string c_disableDST = "DisableAutoDaylightTimeSet"; 
#endif // FEATURE_WIN32_REGISTRY
 
#if FEATURE_CORECLR 
        // use for generating multi-year DST periods
        private static readonly TransitionTime c_transition5_15  = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 05, 15); 
        private static readonly TransitionTime c_transition7_15  = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 07, 15);
        private static readonly TransitionTime c_transition10_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 10, 15);
        private static readonly TransitionTime c_transition12_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 12, 15);
#endif // FEATURE_CORECLR 

        // constants for TimeZoneInfo.Local and TimeZoneInfo.Utc 
        private const string c_utcId = "UTC"; 
        private const string c_localId = "Local";
 
        private const int    c_maxKeyLength = 255;

        private const int    c_regByteLength = 44;
 
        // Number of 100ns ticks per time unit
        private const long c_ticksPerMillisecond = 10000; 
        private const long c_ticksPerSecond      = c_ticksPerMillisecond * 1000; 
        private const long c_ticksPerMinute      = c_ticksPerSecond * 60;
        private const long c_ticksPerHour        = c_ticksPerMinute * 60; 
        private const long c_ticksPerDay         = c_ticksPerHour * 24;
        private const long c_ticksPerDayRange    = c_ticksPerDay - c_ticksPerMillisecond;

        // static method cache & synchronization object 
        private static TimeZoneInfo s_localTimeZone;
        private static TimeZoneInfo s_utcTimeZone; 
#if FEATURE_WIN32_REGISTRY 
        private static ReadOnlyCollection s_readOnlySystemTimeZones;
        private static bool s_allSystemTimeZonesRead = false; 
        private static Dictionary s_hiddenSystemTimeZones;
        private static Dictionary s_systemTimeZones {
            get {
                if (s_hiddenSystemTimeZones == null) { 
                    s_hiddenSystemTimeZones = new Dictionary();
                } 
                return s_hiddenSystemTimeZones; 
            }
            set { 
                s_hiddenSystemTimeZones = value;
            }
        }
 
        // On pre-Vista versions of Windows if you run "cmd /c date" or "cmd /c time" to update the system time
        // the operating system doesn't pick up the correct time zone adjustment rule (it stays on the currently loaded rule). 
        // We need to use the OS API data in this scenario instead of the loaded adjustment rules from the registry for 
        // consistency.  Otherwise DateTime.Now might not match the time displayed in the system tray.  The OS API data for
        // each whole-year is cached below to improve performance. 
        private class OffsetAndRule {
            public int year;
            public TimeSpan offset;
            public AdjustmentRule rule; 
            public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule rule) {
                this.year = year; 
                this.offset = offset; 
                this.rule = rule;
            } 
        }
        [ThreadStatic]
        private static OffsetAndRule s_oneYearLocalFromLocal;
        [ThreadStatic] 
        private static OffsetAndRule s_oneYearLocalFromUtc;
        private static readonly bool c_VistaOrNewer = Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version(6,0); 
 
#endif // FEATURE_WIN32_REGISTRY
 
        private static Object s_hiddenInternalSyncObject;
        private static Object s_internalSyncObject {
            get {
                if (s_hiddenInternalSyncObject == null) { 
                    Object o = new Object();
                    Interlocked.CompareExchange(ref s_hiddenInternalSyncObject, o, null); 
                } 
                return s_hiddenInternalSyncObject;
            } 
        }


 
        // ---- SECTION: public properties --------------*
 
        public String Id { 
            get {
                return m_id; 
            }
        }

        public String DisplayName { 
            get {
                return (m_displayName == null ? String.Empty : m_displayName); 
            } 
        }
 
        public String StandardName {
            get {
                return (m_standardDisplayName == null ? String.Empty : m_standardDisplayName);
            } 
        }
 
        public String DaylightName { 
            get {
                return (m_daylightDisplayName == null? String.Empty : m_daylightDisplayName); 
            }
        }

        public TimeSpan BaseUtcOffset { 
            get {
                return m_baseUtcOffset; 
            } 
        }
 
        public Boolean SupportsDaylightSavingTime {
            get {
                return m_supportsDaylightSavingTime;
            } 
        }
 
 
        // ---- SECTION: public methods --------------*
 
        //
        // GetAdjustmentRules -
        //
        // returns a cloned array of AdjustmentRule objects 
        //
        public AdjustmentRule [] GetAdjustmentRules() { 
            if (m_adjustmentRules == null) { 
                return new AdjustmentRule[0];
            } 
            else {
                return (AdjustmentRule[])m_adjustmentRules.Clone();
            }
        } 

 
        // 
        // GetAmbiguousTimeOffsets -
        // 
        // returns an array of TimeSpan objects representing all of
        // possible UTC offset values for this ambiguous time
        //
        public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset) { 
            if (!SupportsDaylightSavingTime) {
                throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeOffsetIsNotAmbiguous"), "dateTimeOffset"); 
            } 
            Contract.EndContractBlock();
 
            DateTime adjustedTime = (TimeZoneInfo.ConvertTime(dateTimeOffset, this)).DateTime;

            Boolean isAmbiguous = false;
            AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); 
            if (rule != null) {
                DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); 
                isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); 
            }
 
            if (!isAmbiguous) {
                throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeOffsetIsNotAmbiguous"), "dateTimeOffset");
            }
 
            // the passed in dateTime is ambiguous in this TimeZoneInfo instance
            TimeSpan[] timeSpans = new TimeSpan[2]; 
 
            // the TimeSpan array must be sorted from least to greatest
            if (rule.DaylightDelta > TimeSpan.Zero) { 
                timeSpans[0] = m_baseUtcOffset; //
                timeSpans[1] = m_baseUtcOffset + rule.DaylightDelta;
            }
            else { 
                timeSpans[0] = m_baseUtcOffset + rule.DaylightDelta;
                timeSpans[1] = m_baseUtcOffset; // 
            } 
            return timeSpans;
        } 


        public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime) {
            if (!SupportsDaylightSavingTime) { 
                throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeIsNotAmbiguous"), "dateTime");
            } 
            Contract.EndContractBlock(); 

            DateTime adjustedTime; 
            if (dateTime.Kind == DateTimeKind.Local) {
                lock (s_internalSyncObject) {
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, this);
                } 
            }
            else if (dateTime.Kind == DateTimeKind.Utc) { 
                lock (s_internalSyncObject) { 
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Utc, this);
                } 
            }
            else {
                adjustedTime = dateTime;
            } 

            Boolean isAmbiguous = false; 
            AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); 
            if (rule != null) {
                DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); 
                isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime);
            }

            if (!isAmbiguous) { 
                throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeIsNotAmbiguous"), "dateTime");
            } 
 
            // the passed in dateTime is ambiguous in this TimeZoneInfo instance
            TimeSpan[] timeSpans = new TimeSpan[2]; 

            // the TimeSpan array must be sorted from least to greatest
            if (rule.DaylightDelta > TimeSpan.Zero) {
                timeSpans[0] = m_baseUtcOffset; // 
                timeSpans[1] = m_baseUtcOffset + rule.DaylightDelta;
            } 
            else { 
                timeSpans[0] = m_baseUtcOffset + rule.DaylightDelta;
                timeSpans[1] = m_baseUtcOffset; // 
            }
            return timeSpans;
        }
 
        //
        // GetUtcOffset - 
        // 
        // returns the Universal Coordinated Time (UTC) Offset
        // for the current TimeZoneInfo instance. 
        //
        public TimeSpan GetUtcOffset(DateTimeOffset dateTimeOffset) {
            return GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this);
        } 

 
        public TimeSpan GetUtcOffset(DateTime dateTime) { 
            return GetUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime);
        } 

        internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) {
            if (dateTime.Kind == DateTimeKind.Local) {
                DateTime adjustedTime; 
                lock (s_internalSyncObject) {
                    if (GetCorrespondingKind() == DateTimeKind.Local) { 
                        // 
                        // Special-case for TimeZoneInfo.Local.GetUtcOffset(date)
                        // to handle an edge case with Invalid-Times for DateTime formatting: 
                        //
                        // Consider the invalid PST time "2007-03-11T02:00:00.0000000-08:00"
                        //
                        // By directly calling GetUtcOffset instead of converting to UTC and then calling GetUtcOffsetFromUtc 
                        // the correct invalid offset of "-08:00" is returned.  In the normal case of converting to UTC as an
                        // interim-step, the invalid time is adjusted into a *valid* UTC time which causes a change in output: 
                        // 
                        // 1) invalid PST time "2007-03-11T02:00:00.0000000-08:00"
                        // 2) converted to UTC "2007-03-11T10:00:00.0000000Z" 
                        // 3) offset returned  "2007-03-11T03:00:00.0000000-07:00"
                        //
                        return GetUtcOffset(dateTime, this, flags);
                    } 
                    //
                    // normal case of converting from Local to Utc and then getting the offset from the UTC DateTime 
                    // 
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, TimeZoneInfo.Utc, flags);
                } 
                return GetUtcOffsetFromUtc(adjustedTime, this);
            }
            else if (dateTime.Kind == DateTimeKind.Utc) {
                if (GetCorrespondingKind() == DateTimeKind.Utc) { 
                    return m_baseUtcOffset;
                } 
                else { 
                    //
                    // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a 
                    // special Loss-Less case.
                    //
                    return GetUtcOffsetFromUtc(dateTime, this);
                } 
            }
 
            return GetUtcOffset(dateTime, this, flags); 
        }
 

        //
        // IsAmbiguousTime -
        // 
        // returns true if the time is during the ambiguous time period
        // for the current TimeZoneInfo instance. 
        // 
        public Boolean IsAmbiguousTime(DateTimeOffset dateTimeOffset) {
            if (!m_supportsDaylightSavingTime) { 
                return false;
            }

            DateTimeOffset adjustedTime = TimeZoneInfo.ConvertTime(dateTimeOffset, this); 
            return IsAmbiguousTime(adjustedTime.DateTime);
        } 
 

        public Boolean IsAmbiguousTime(DateTime dateTime) { 
            return IsAmbiguousTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime);
        }

        internal Boolean IsAmbiguousTime(DateTime dateTime, TimeZoneInfoOptions flags) { 
            if (!m_supportsDaylightSavingTime) {
                return false; 
            } 

            DateTime adjustedTime; 
            if (dateTime.Kind == DateTimeKind.Local) {
                lock (s_internalSyncObject) {
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, this, flags);
                } 
            }
            else if (dateTime.Kind == DateTimeKind.Utc) { 
                lock (s_internalSyncObject) { 
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Utc, this, flags);
                } 
            }
            else {
                adjustedTime = dateTime;
            } 

 
            AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); 
            if (rule != null) {
                DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); 
                return GetIsAmbiguousTime(adjustedTime, rule, daylightTime);
            }
            return false;
        } 

 
 
        //
        // IsDaylightSavingTime - 
        //
        // Returns true if the time is during Daylight Saving time
        // for the current TimeZoneInfo instance.
        // 
        public Boolean IsDaylightSavingTime(DateTimeOffset dateTimeOffset) {
            Boolean isDaylightSavingTime; 
            GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out isDaylightSavingTime); 
            return isDaylightSavingTime;
        } 


        public Boolean IsDaylightSavingTime(DateTime dateTime) {
            return IsDaylightSavingTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); 
        }
 
        internal Boolean IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags) { 
            //
            //    dateTime.Kind is UTC, then time will be converted from UTC 
            //        into current instance's timezone
            //    dateTime.Kind is Local, then time will be converted from Local
            //        into current instance's timezone
            //    dateTime.Kind is UnSpecified, then time is already in 
            //        current instance's timezone
            // 
            // Our DateTime handles ambiguous times, (one is in the daylight and 
            // one is in standard.) If a new DateTime is constructed during ambiguous
            // time, it is defaulted to "Standard" (i.e. this will return false). 
            // For Invalid times, we will return false

            if (!m_supportsDaylightSavingTime || m_adjustmentRules == null) {
                return false; 
            }
 
            DateTime adjustedTime; 
            //
            // handle any Local/Utc special cases... 
            //
            if (dateTime.Kind == DateTimeKind.Local) {
                lock (s_internalSyncObject) {
                    adjustedTime = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, this, flags); 
                }
            } 
            else if (dateTime.Kind == DateTimeKind.Utc) { 
                if (GetCorrespondingKind() == DateTimeKind.Utc) {
                    // simple always false case: TimeZoneInfo.Utc.IsDaylightSavingTime(dateTime, flags); 
                    return false;
                }
                else {
                    // 
                    // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a
                    // special Loss-Less case. 
                    // 
                    Boolean isDaylightSavings;
                    GetUtcOffsetFromUtc(dateTime, this, out isDaylightSavings); 
                    return isDaylightSavings;
                }
            }
            else { 
                adjustedTime = dateTime;
            } 
 
            //
            // handle the normal cases... 
            //
            AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime);
            if (rule != null) {
                DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); 
                return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags);
            } 
            else { 
                return false;
            } 
        }


        // 
        // IsInvalidTime -
        // 
        // returns true when dateTime falls into a "hole in time". 
        //
        public Boolean IsInvalidTime(DateTime dateTime) { 
            Boolean isInvalid = false;

            if ( (dateTime.Kind == DateTimeKind.Unspecified)
            ||   (dateTime.Kind == DateTimeKind.Local && GetCorrespondingKind() == DateTimeKind.Local) ) { 

                // only check Unspecified and (Local when this TimeZoneInfo instance is Local) 
                AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime); 

 
                if (rule != null) {
                    DaylightTime daylightTime = GetDaylightTime(dateTime.Year, rule);
                    isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime);
                } 
                else {
                    isInvalid = false; 
                } 
            }
 
            return isInvalid;
        }

 
        //
        // ClearCachedData - 
        // 
        // Clears data from static members
        // 
        static public void ClearCachedData() {
            lock (s_internalSyncObject) {
                s_localTimeZone = null;
                s_utcTimeZone = null; 
#if FEATURE_WIN32_REGISTRY
                s_systemTimeZones = null; 
                s_readOnlySystemTimeZones = null; 
                s_allSystemTimeZonesRead = false;
                s_oneYearLocalFromLocal = null; 
                s_oneYearLocalFromUtc = null;
#endif // FEATURE_WIN32_REGISTRY
            }
        } 

 
#if FEATURE_WIN32_REGISTRY 
        //
        // ConvertTimeBySystemTimeZoneId - 
        //
        // Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone
        //
        static public DateTimeOffset ConvertTimeBySystemTimeZoneId(DateTimeOffset dateTimeOffset, String destinationTimeZoneId) { 
            return ConvertTime(dateTimeOffset, FindSystemTimeZoneById(destinationTimeZoneId));
        } 
#endif // FEATURE_WIN32_REGISTRY 

 
#if FEATURE_WIN32_REGISTRY
        static public DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, String destinationTimeZoneId) {
                return ConvertTime(dateTime, FindSystemTimeZoneById(destinationTimeZoneId));
        } 
#endif // FEATURE_WIN32_REGISTRY
 
#if FEATURE_WIN32_REGISTRY 
        static public DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, String sourceTimeZoneId, String destinationTimeZoneId) {
            if (dateTime.Kind == DateTimeKind.Local && String.Compare(sourceTimeZoneId, TimeZoneInfo.Local.Id, StringComparison.OrdinalIgnoreCase) == 0) { 
                // TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData.
                // Take a lock to guarantee this method will not be impacted by the ClearCachedData call.
                // Without the lock, there is a chance that ConvertTime will throw since 'source' won't
                // be reference equal to the new TimeZoneInfo.Local 
                //
                lock (s_internalSyncObject) { 
                    return ConvertTime(dateTime, TimeZoneInfo.Local, FindSystemTimeZoneById(destinationTimeZoneId)); 
                }
            } 
            else if (dateTime.Kind == DateTimeKind.Utc && String.Compare(sourceTimeZoneId, TimeZoneInfo.Utc.Id, StringComparison.OrdinalIgnoreCase) == 0) {
                // TimeZoneInfo.Utc can be cleared by another thread calling TimeZoneInfo.ClearCachedData.
                // Take a lock to guarantee this method will not be impacted by the ClearCachedData call.
                // Without the lock, there is a chance that ConvertTime will throw since 'source' won't 
                // be reference equal to the new TimeZoneInfo.Utc
                // 
                lock (s_internalSyncObject) { 
                    return ConvertTime(dateTime, TimeZoneInfo.Utc, FindSystemTimeZoneById(destinationTimeZoneId));
                } 
            }
            else {
                return ConvertTime(dateTime, FindSystemTimeZoneById(sourceTimeZoneId), FindSystemTimeZoneById(destinationTimeZoneId));
            } 
        }
#endif // FEATURE_WIN32_REGISTRY 
 

        // 
        // ConvertTime -
        //
        // Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone
        // 

        static public DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) { 
            if (destinationTimeZone == null) { 
                throw new ArgumentNullException("destinationTimeZone");
            } 

            Contract.EndContractBlock();
            // calculate the destination time zone offset
            DateTime utcDateTime = dateTimeOffset.UtcDateTime; 
            TimeSpan destinationOffset = GetUtcOffsetFromUtc(utcDateTime, destinationTimeZone);
 
            // check for overflow 
            Int64 ticks = utcDateTime.Ticks + destinationOffset.Ticks;
 
            if (ticks > DateTimeOffset.MaxValue.Ticks) {
                return DateTimeOffset.MaxValue;
            }
            else if (ticks < DateTimeOffset.MinValue.Ticks) { 
                return DateTimeOffset.MinValue;
            } 
            else { 
                return new DateTimeOffset(ticks, destinationOffset);
            } 
        }

        static public DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) {
            if (destinationTimeZone == null) { 
                throw new ArgumentNullException("destinationTimeZone");
            } 
            Contract.EndContractBlock(); 

            if (dateTime.Kind == DateTimeKind.Utc) { 
                lock (s_internalSyncObject) {
                    return ConvertTime(dateTime, TimeZoneInfo.Utc, destinationTimeZone);
                }
            } 
            else {
                lock (s_internalSyncObject) { 
                    return ConvertTime(dateTime, TimeZoneInfo.Local, destinationTimeZone); 
                }
            } 
        }

        static public DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) {
            return ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None); 
        }
 
 
        static internal DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags) {
            if (sourceTimeZone == null) { 
                throw new ArgumentNullException("sourceTimeZone");
            }

            if (destinationTimeZone == null) { 
                throw new ArgumentNullException("destinationTimeZone");
            } 
            Contract.EndContractBlock(); 

            DateTimeKind sourceKind = sourceTimeZone.GetCorrespondingKind(); 
            if ( ((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && (dateTime.Kind != DateTimeKind.Unspecified) && (dateTime.Kind != sourceKind) ) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_ConvertMismatch"), "sourceTimeZone");
            }
 
            //
            // check to see if the DateTime is in an invalid time range.  This check 
            // requires the current AdjustmentRule and DaylightTime - which are also 
            // needed to calculate 'sourceOffset' in the normal conversion case.
            // By calculating the 'sourceOffset' here we improve the 
            // performance for the normal case at the expense of the 'ArgumentException'
            // case and Loss-less Local special cases.
            //
            AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime); 
            TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset;
 
            if (sourceRule != null) { 
                Boolean sourceIsDaylightSavings = false;
                DaylightTime sourceDaylightTime = GetDaylightTime(dateTime.Year, sourceRule); 

                // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule
                // period that supports DST
                if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && GetIsInvalidTime(dateTime, sourceRule, sourceDaylightTime)) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeIsInvalid"), "dateTime");
                } 
                sourceIsDaylightSavings = GetIsDaylightSavings(dateTime, sourceRule, sourceDaylightTime, flags); 

                // adjust the sourceOffset according to the Adjustment Rule / Daylight Saving Rule 
                sourceOffset += (sourceIsDaylightSavings ? sourceRule.DaylightDelta : TimeSpan.Zero /**/);
            }

            DateTimeKind targetKind = destinationTimeZone.GetCorrespondingKind(); 

            // handle the special case of Loss-less Local->Local and UTC->UTC) 
            if (dateTime.Kind != DateTimeKind.Unspecified && sourceKind != DateTimeKind.Unspecified 
                && sourceKind == targetKind) {
                return dateTime; 
            }

            Int64 utcTicks = dateTime.Ticks - sourceOffset.Ticks;
 
            // handle the normal case by converting from 'source' to UTC and then to 'target'
            Boolean isAmbiguousLocalDst = false; 
            DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out isAmbiguousLocalDst); 

            if (targetKind == DateTimeKind.Local) { 
                // Because the ticks conversion between UTC and local is lossy, we need to capture whether the
                // time is in a repeated hour so that it can be passed to the DateTime constructor.
                return new DateTime(targetConverted.Ticks, DateTimeKind.Local, isAmbiguousLocalDst);
            } 
            else {
                return new DateTime(targetConverted.Ticks, targetKind); 
            } 
        }
 


        //
        // ConvertTimeFromUtc - 
        //
        // Converts the value of a DateTime object from Coordinated Universal Time (UTC) to 
        // the destinationTimeZone. 
        //
        static public DateTime ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone) { 
            lock (s_internalSyncObject) {
                return ConvertTime(dateTime, TimeZoneInfo.Utc, destinationTimeZone);
            }
        } 

 
        // 
        // ConvertTimeToUtc -
        // 
        // Converts the value of a DateTime object to Coordinated Universal Time (UTC).
        //
        static public DateTime ConvertTimeToUtc(DateTime dateTime) {
            if (dateTime.Kind == DateTimeKind.Utc) { 
                return dateTime;
            } 
            lock (s_internalSyncObject) { 
                return ConvertTime(dateTime, TimeZoneInfo.Local, TimeZoneInfo.Utc);
            } 
        }


        static internal DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags) { 
            if (dateTime.Kind == DateTimeKind.Utc) {
                return dateTime; 
            } 
            lock (s_internalSyncObject) {
                return ConvertTime(dateTime, TimeZoneInfo.Local, TimeZoneInfo.Utc, flags); 
            }
        }

        static public DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfo sourceTimeZone) { 
            lock (s_internalSyncObject) {
                return ConvertTime(dateTime, sourceTimeZone, TimeZoneInfo.Utc); 
            } 
        }
 

        //
        // IEquatable.Equals -
        // 
        // returns value equality.  Equals does not compare any localizable
        // String objects (DisplayName, StandardName, DaylightName). 
        // 
        public bool Equals(TimeZoneInfo other) {
            return (other != null && String.Compare(this.m_id, other.m_id, StringComparison.OrdinalIgnoreCase) == 0 && HasSameRules(other)); 
        }

#if FEATURE_WIN32_REGISTRY
        // 
        // FindSystemTimeZoneById -
        // 
        // Looks up a TimeZoneInfo by System ID.  Throws TimeZoneNotFoundException 
        // and InvalidTimeZoneException.
        // 
        //
        static public TimeZoneInfo FindSystemTimeZoneById(string id) {
            // Special case for Utc as it will not exist in the dictionary with the rest
            // of the system time zones.  There is no need to do this check for Local.Id 
            // since Local is a real time zone that exists in the dictionary cache
            if (String.Compare(id, c_utcId, StringComparison.OrdinalIgnoreCase) == 0) { 
                return TimeZoneInfo.Utc; 
            }
            lock (s_internalSyncObject) { 
                return GetTimeZone(id);
            }
        }
#endif // FEATURE_WIN32_REGISTRY 

        // 
        // FromSerializedString - 
        //
        static public TimeZoneInfo FromSerializedString(string source) { 
            if (source == null) {
                throw new ArgumentNullException("source");
            }
            if (source.Length == 0) { 
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSerializedString", source), "source");
            } 
            Contract.EndContractBlock(); 

            return StringSerializer.GetDeserializedTimeZoneInfo(source); 
        }


        // 
        // GetHashCode -
        // 
        public override int GetHashCode() { 
            return m_id.ToUpper(CultureInfo.InvariantCulture).GetHashCode();
        } 


#if FEATURE_WIN32_REGISTRY
        // 
        // GetSystemTimeZones -
        // 
        // returns a ReadOnlyCollection containing all valid TimeZone's 
        // from the local machine.  The entries in the collection are sorted by
        // 'DisplayName'. 
        //
        // This method does *not* throw TimeZoneNotFoundException or
        // InvalidTimeZoneException.
        // 
        // 
        //  
        //  
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        // @
        static public ReadOnlyCollection GetSystemTimeZones() {
            lock (s_internalSyncObject) {
                if (!s_allSystemTimeZonesRead) { 
                    PermissionSet permSet = new PermissionSet(PermissionState.None);
                    permSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, c_timeZonesRegistryHivePermissionList)); 
                    permSet.Assert(); 

                    using (RegistryKey reg = Registry.LocalMachine.OpenSubKey( 
                                      c_timeZonesRegistryHive,
#if FEATURE_MACL
                                      RegistryKeyPermissionCheck.Default,
                                      System.Security.AccessControl.RegistryRights.ReadKey 
#else
                                      false 
#endif 
                                      )) {
 
                        if (reg == null) {
                            // the entire Time Zones registry hive is missing!
                            //
                            List systemList; 
                            if (s_systemTimeZones != null) {
                                // return a collection of the cached system time zones 
                                systemList = new List(s_systemTimeZones.Values); 
                            }
                            else { 
                                // return an empty collection
                                systemList = new List();
                            }
                            s_readOnlySystemTimeZones = new ReadOnlyCollection(systemList); 
                            s_allSystemTimeZonesRead = true;
                            return s_readOnlySystemTimeZones; 
                        } 

                        foreach (string keyName in reg.GetSubKeyNames()) { 
                            TimeZoneInfo value;
                            Exception ex;
                            TryGetTimeZone(keyName, false, out value, out ex);  // populate the cache
                        } 
                    }
 
 
                    // sort and copy the TimeZoneInfo's into a ReadOnlyCollection for the user
                    IComparer comparer = new TimeZoneInfoComparer(); 
                    List list = new List(s_systemTimeZones.Values);
                    list.Sort(comparer);

                    s_readOnlySystemTimeZones = new ReadOnlyCollection(list); 
                    s_allSystemTimeZonesRead = true;
                } 
                return s_readOnlySystemTimeZones; 
            }
        } 
#endif // FEATURE_WIN32_REGISTRY


        // 
        // HasSameRules -
        // 
        // Value equality on the "adjustmentRules" array 
        //
        public Boolean HasSameRules(TimeZoneInfo other) { 
            if (other == null) {
                throw new ArgumentNullException("other");
            }
 
            // check the utcOffset and supportsDaylightSavingTime members
            Contract.EndContractBlock(); 
 
            if (this.m_baseUtcOffset != other.m_baseUtcOffset
            || this.m_supportsDaylightSavingTime != other.m_supportsDaylightSavingTime) { 
                return false;
            }

            bool sameRules; 
            AdjustmentRule[] currentRules = this.m_adjustmentRules;
            AdjustmentRule[] otherRules = other.m_adjustmentRules; 
 
            sameRules = (currentRules == null && otherRules == null)
                      ||(currentRules != null && otherRules != null); 

            if (!sameRules) {
                // AdjustmentRule array mismatch
                return false; 
            }
 
            if (currentRules != null) { 
                if (currentRules.Length != otherRules.Length) {
                    // AdjustmentRule array length mismatch 
                    return false;
                }

                for(int i = 0; i < currentRules.Length; i++) { 
                    if (!(currentRules[i]).Equals(otherRules[i])) {
                        // AdjustmentRule value-equality mismatch 
                        return false; 
                    }
                } 

            }
            return sameRules;
        } 

        // 
        // Local - 
        //
        // returns a TimeZoneInfo instance that represents the local time on the machine. 
        // Accessing this property may throw InvalidTimeZoneException or COMException
        // if the machine is in an unstable or corrupt state.
        //
        static public TimeZoneInfo Local { 
            get {
                Contract.Ensures(Contract.Result() != null); 
 
                TimeZoneInfo local = s_localTimeZone;
                if (local == null) { 
                    lock (s_internalSyncObject) {
                        if (s_localTimeZone == null) {
                            TimeZoneInfo tempLocal = GetLocalTimeZone();
 
                            // copy tempLocal to s_localTimeZone -
                            // this step is to break the reference equality 
                            // between TimeZoneInfo.Local and a second time zone 
                            // such as "Pacific Standard Time"
                            s_localTimeZone = new TimeZoneInfo( 
                                              tempLocal.m_id,
                                              tempLocal.m_baseUtcOffset,
                                              tempLocal.m_displayName,
                                              tempLocal.m_standardDisplayName, 
                                              tempLocal.m_daylightDisplayName,
                                              tempLocal.m_adjustmentRules, 
                                              false); 
                        }
                        local = s_localTimeZone; 
                    }
                }
                return local;
            } 
        }
 
 
        //
        // ToSerializedString - 
        //
        // "TimeZoneInfo"           := TimeZoneInfo Data;[AdjustmentRule Data 1];...;[AdjustmentRule Data N]
        //
        // "TimeZoneInfo Data"      := ;;; 
        //                          ;;
        // 
        // "AdjustmentRule Data" := ;;; 
        //                          [TransitionTime Data DST Start]
        //                          [TransitionTime Data DST End] 
        //
        // "TransitionTime Data" += ;;;;
        //
        public String ToSerializedString() { 
            return StringSerializer.GetSerializedString(this);
        } 
 

        // 
        // ToString -
        //
        // returns the DisplayName:
        // "(GMT-08:00) Pacific Time (US & Canada); Tijuana" 
        //
        public override string ToString() { 
            return this.DisplayName; 
        }
 

        //
        // Utc -
        // 
        // returns a TimeZoneInfo instance that represents Universal Coordinated Time (UTC)
        // 
        static public TimeZoneInfo Utc { 
            get {
                Contract.Ensures(Contract.Result() != null); 

                TimeZoneInfo utc = s_utcTimeZone;
                if (utc == null) {
                    lock (s_internalSyncObject) { 
                        if (s_utcTimeZone == null) {
                            s_utcTimeZone = CreateCustomTimeZone(c_utcId, TimeSpan.Zero, c_utcId, c_utcId); 
                        } 
                        utc = s_utcTimeZone;
                    } 
                }
                return utc;
            }
        } 

 
        // -------- SECTION: constructors -----------------* 
        //
        // TimeZoneInfo - 
        //
        // private ctor
        //
        [System.Security.SecurityCritical]  // auto-generated 
        private TimeZoneInfo(Win32Native.TimeZoneInformation zone, Boolean dstDisabled) {
 
            if (String.IsNullOrEmpty(zone.StandardName)) { 
                m_id = c_localId;  // the ID must contain at least 1 character - initialize m_id to "Local"
            } 
            else {
                m_id = zone.StandardName;
            }
            m_baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0); 

            if (!dstDisabled) { 
                // only create the adjustment rule if DST is enabled 
                Win32Native.RegistryTimeZoneInformation regZone = new Win32Native.RegistryTimeZoneInformation(zone);
                AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date); 
                if (rule != null) {
                    m_adjustmentRules = new AdjustmentRule[1];
                    m_adjustmentRules[0] = rule;
                } 
            }
 
            ValidateTimeZoneInfo(m_id, m_baseUtcOffset, m_adjustmentRules, out m_supportsDaylightSavingTime); 
            m_displayName = zone.StandardName;
            m_standardDisplayName = zone.StandardName; 
            m_daylightDisplayName = zone.DaylightName;
        }

#if FEATURE_CORECLR 
        private TimeZoneInfo(Byte[] data, Boolean dstDisabled) {
            TZifHead t; 
            DateTime[] dts; 
            Byte[] typeOfLocalTime;
            TZifType[] transitionType; 
            String zoneAbbreviations;
            Boolean[] StandardTime;
            Boolean[] GmtTime;
 
            // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed.
            TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime); 
 
            m_id = c_localId;
            m_displayName = c_localId; 
            m_baseUtcOffset = TimeSpan.Zero;

            // find the best matching baseUtcOffset and display strings based on the current utcNow value
            DateTime utcNow = DateTime.UtcNow; 
            for (int i = 0; i < dts.Length && dts[i] <= utcNow; i++) {
                int type = typeOfLocalTime[i]; 
                if (!transitionType[type].IsDst) { 
                    m_baseUtcOffset = transitionType[type].UtcOffset;
                    m_standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); 
                }
                else {
                    m_daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex);
                } 
            }
 
            if (dts.Length == 0) { 
                // time zones like Africa/Bujumbura and Etc/GMT* have no transition times but still contain
                // TZifType entries that may contain a baseUtcOffset and display strings 
                for (int i = 0; i < transitionType.Length; i++) {
                    if (!transitionType[i].IsDst) {
                        m_baseUtcOffset = transitionType[i].UtcOffset;
                        m_standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); 
                    }
                    else { 
                        m_daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); 
                    }
                } 
            }
            m_id = m_standardDisplayName;
            m_displayName = m_standardDisplayName;
 
            // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns
            // with DateTimeOffset, SQL Server, and the W3C XML Specification 
            if (m_baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) { 
                m_baseUtcOffset = new TimeSpan(m_baseUtcOffset.Hours, m_baseUtcOffset.Minutes, 0);
            } 

            if (!dstDisabled) {
                // only create the adjustment rule if DST is enabled
                TZif_GenerateAdjustmentRules(out m_adjustmentRules, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime); 
            }
 
            ValidateTimeZoneInfo(m_id, m_baseUtcOffset, m_adjustmentRules, out m_supportsDaylightSavingTime); 
        }
#endif // FEATURE_CORECLR 

        private TimeZoneInfo(
                String id,
                TimeSpan baseUtcOffset, 
                String displayName,
                String standardDisplayName, 
                String daylightDisplayName, 
                AdjustmentRule [] adjustmentRules,
                Boolean disableDaylightSavingTime) { 

            Boolean adjustmentRulesSupportDst;
            ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out adjustmentRulesSupportDst);
 
            if (!disableDaylightSavingTime && adjustmentRules != null && adjustmentRules.Length > 0) {
                m_adjustmentRules = (AdjustmentRule[])adjustmentRules.Clone(); 
            } 

            m_id = id; 
            m_baseUtcOffset = baseUtcOffset;
            m_displayName = displayName;
            m_standardDisplayName = standardDisplayName;
            m_daylightDisplayName = (disableDaylightSavingTime ? null : daylightDisplayName); 
            m_supportsDaylightSavingTime = adjustmentRulesSupportDst && !disableDaylightSavingTime;
        } 
 
        // -------- SECTION: factory methods -----------------*
 
        //
        // CreateCustomTimeZone -
        //
        // returns a simple TimeZoneInfo instance that does 
        // not support Daylight Saving Time
        // 
        static public TimeZoneInfo CreateCustomTimeZone( 
                String id,
                TimeSpan baseUtcOffset, 
                String displayName,
                  String standardDisplayName) {

            return new TimeZoneInfo( 
                           id,
                           baseUtcOffset, 
                           displayName, 
                           standardDisplayName,
                           standardDisplayName, 
                           null,
                           false);
        }
 
        //
        // CreateCustomTimeZone - 
        // 
        // returns a TimeZoneInfo instance that may
        // support Daylight Saving Time 
        //
        static public TimeZoneInfo CreateCustomTimeZone(
                String id,
                TimeSpan baseUtcOffset, 
                String displayName,
                String standardDisplayName, 
                String daylightDisplayName, 
                AdjustmentRule [] adjustmentRules) {
 
            return new TimeZoneInfo(
                           id,
                           baseUtcOffset,
                           displayName, 
                           standardDisplayName,
                           daylightDisplayName, 
                           adjustmentRules, 
                           false);
        } 


        //
        // CreateCustomTimeZone - 
        //
        // returns a TimeZoneInfo instance that may 
        // support Daylight Saving Time 
        //
        // This class factory method is identical to the 
        // TimeZoneInfo private constructor
        //
        static public TimeZoneInfo CreateCustomTimeZone(
                String id, 
                TimeSpan baseUtcOffset,
                String displayName, 
                String standardDisplayName, 
                String daylightDisplayName,
                AdjustmentRule [] adjustmentRules, 
                Boolean disableDaylightSavingTime) {

           return new TimeZoneInfo(
                           id, 
                           baseUtcOffset,
                           displayName, 
                           standardDisplayName, 
                           daylightDisplayName,
                           adjustmentRules, 
                           disableDaylightSavingTime);
        }

 

        // ----- SECTION: private serialization instance methods  ----------------* 
 
#if FEATURE_SERIALIZATION
        void IDeserializationCallback.OnDeserialization(Object sender) { 
            try {
                Boolean adjustmentRulesSupportDst;
                ValidateTimeZoneInfo(m_id, m_baseUtcOffset, m_adjustmentRules, out adjustmentRulesSupportDst);
 
                if (adjustmentRulesSupportDst != m_supportsDaylightSavingTime) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_CorruptField", "SupportsDaylightSavingTime")); 
                } 
            }
            catch (ArgumentException e) { 
                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
            }
            catch (InvalidTimeZoneException e) {
                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e); 
            }
        } 
 

        [System.Security.SecurityCritical]  // auto-generated_required 
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
            if (info == null) {
                throw new ArgumentNullException("info");
            } 
            Contract.EndContractBlock();
 
            info.AddValue("Id", m_id); 
            info.AddValue("DisplayName", m_displayName);
            info.AddValue("StandardName", m_standardDisplayName); 
            info.AddValue("DaylightName", m_daylightDisplayName);
            info.AddValue("BaseUtcOffset", m_baseUtcOffset);
            info.AddValue("AdjustmentRules", m_adjustmentRules);
            info.AddValue("SupportsDaylightSavingTime", m_supportsDaylightSavingTime); 
        }
 
 
        TimeZoneInfo(SerializationInfo info, StreamingContext context) {
            if (info == null) { 
                throw new ArgumentNullException("info");
            }

            m_id                  = (String)info.GetValue("Id", typeof(String)); 
            m_displayName         = (String)info.GetValue("DisplayName", typeof(String));
            m_standardDisplayName = (String)info.GetValue("StandardName", typeof(String)); 
            m_daylightDisplayName = (String)info.GetValue("DaylightName", typeof(String)); 
            m_baseUtcOffset       = (TimeSpan)info.GetValue("BaseUtcOffset", typeof(TimeSpan));
            m_adjustmentRules     = (AdjustmentRule[])info.GetValue("AdjustmentRules", typeof(AdjustmentRule[])); 
            m_supportsDaylightSavingTime = (Boolean)info.GetValue("SupportsDaylightSavingTime", typeof(Boolean));
        }
#endif
 

 
        // ----- SECTION: internal instance utility methods ----------------* 

 
        // assumes dateTime is in the current time zone's time
        [System.Security.SecuritySafeCritical]
        private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime) {
            if (m_adjustmentRules == null || m_adjustmentRules.Length == 0) { 
                return null;
            } 
 
#if FEATURE_WIN32_REGISTRY
            // On pre-Vista versions of Windows if you run "cmd /c date" or "cmd /c time" to update the system time 
            // the operating system doesn't pick up the correct time zone adjustment rule (it stays on the currently loaded rule).
            // We need to use the OS API data in this scenario instead of the loaded adjustment rules from the registry for
            // consistency.  Otherwise DateTime.Now might not match the time displayed in the system tray.
            if (!c_VistaOrNewer && GetCorrespondingKind() == DateTimeKind.Local) { 
                return GetOneYearLocalFromLocal(dateTime.Year).rule;
            } 
#endif 
            // Only check the whole-date portion of the dateTime -
            // This is because the AdjustmentRule DateStart & DateEnd are stored as 
            // Date-only values {4/2/2006 - 10/28/2006} but actually represent the
            // time span {4/2/2006@00:00:00.00000 - 10/28/2006@23:59:59.99999}
            DateTime date = dateTime.Date;
 
            for (int i = 0; i < m_adjustmentRules.Length; i++) {
                if (m_adjustmentRules[i].DateStart <= date && m_adjustmentRules[i].DateEnd >= date) { 
                    return m_adjustmentRules[i]; 
                }
            } 

            return null;
        }
 

        // 
        // GetCorrespondingKind- 
        //
        // Instance Helper function that returns the corresponding DateTimeKind for this TimeZoneInfo 
        //
        private DateTimeKind GetCorrespondingKind() {
            DateTimeKind kind;
 
            //
            // we check reference equality to see if 'this' is the same as 
            // TimeZoneInfo.Local or TimeZoneInfo.Utc.  This check is needed to 
            // support setting the DateTime Kind property to 'Local' or
            // 'Utc' on the ConverTime(...) return value. 
            //
            // Using reference equality instead of value equality was a
            // performance based design compromise.  The reference equality
            // has much greater performance, but it reduces the number of 
            // returned DateTime's that can be properly set as 'Local' or 'Utc'.
            // 
            // For example, the user could be converting to the TimeZoneInfo returned 
            // by FindSystemTimeZoneById("Pacific Standard Time") and their local
            // machine may be in Pacific time.  If we used value equality to determine 
            // the corresponding Kind then this conversion would be tagged as 'Local';
            // where as we are currently tagging the returned DateTime as 'Unspecified'
            // in this example.  Only when the user passes in TimeZoneInfo.Local or
            // TimeZoneInfo.Utc to the ConvertTime(...) methods will this check succeed. 
            //
            if ((object)this == (object)s_utcTimeZone) { 
                kind = DateTimeKind.Utc; 
            }
            else if ((object)this == (object)s_localTimeZone) { 
                kind = DateTimeKind.Local;
            }
            else {
                kind = DateTimeKind.Unspecified; 
            }
 
            return kind; 
        }
 


        // ----- SECTION: internal static utility methods ----------------*
 
#if FEATURE_WIN32_REGISTRY
        // 
        // CheckDaylightSavingTimeDisabledDownlevel - 
        //
        // Helper function to check if the O/S has Daylight Saving Time Disabled.  This check returns 
        // true when the 'DisableAutoDaylightTimeSet' or 'DynamicDaylightTimeDisabled' REG_DWORD keys are set to 1
        //
        // This check is only meant to be used for "Local".
        // 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        // @ 
        static private Boolean CheckDaylightSavingTimeDisabledDownlevel() {
            // Vista and newer: 
            if (c_VistaOrNewer) {
                return false;
            }
 
            // Legacy downlevel:
            try { 
                PermissionSet permSet = new PermissionSet(PermissionState.None); 
                permSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, c_timeZoneInfoRegistryHivePermissionList));
                permSet.Assert(); 

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(
                                  c_timeZoneInfoRegistryHive,
#if FEATURE_MACL 
                                  RegistryKeyPermissionCheck.Default,
                                  System.Security.AccessControl.RegistryRights.ReadKey 
#else 
                                  false
#endif 
                                  )) {

                    if (key == null) {
                        return false; 
                    }
 
                    Int32 disabled = 0; 

                    try { 
                        disabled = (Int32)key.GetValue(c_disableDST, 0, RegistryValueOptions.None);
                    }
                    catch (InvalidCastException) {
                    } 

                    if (disabled == 1) { 
                        return true; 
                    }
                } 
            }
            finally {
                PermissionSet.RevertAssert();
            } 
            return false;
        } 
#endif // FEATURE_WIN32_REGISTRY 

        // 
        // CheckDaylightSavingTimeNotSupported -
        //
        // Helper function to check if the current TimeZoneInformation struct does not support DST.  This
        // check returns true when the DaylightDate == StandardDate 
        //
        // This check is only meant to be used for "Local". 
        // 
        [System.Security.SecurityCritical]  // auto-generated
        static private Boolean CheckDaylightSavingTimeNotSupported(Win32Native.TimeZoneInformation timeZone) { 
            return (   timeZone.DaylightDate.Year         == timeZone.StandardDate.Year
                    && timeZone.DaylightDate.Month        == timeZone.StandardDate.Month
                    && timeZone.DaylightDate.DayOfWeek    == timeZone.StandardDate.DayOfWeek
                    && timeZone.DaylightDate.Day          == timeZone.StandardDate.Day 
                    && timeZone.DaylightDate.Hour         == timeZone.StandardDate.Hour
                    && timeZone.DaylightDate.Minute       == timeZone.StandardDate.Minute 
                    && timeZone.DaylightDate.Second       == timeZone.StandardDate.Second 
                    && timeZone.DaylightDate.Milliseconds == timeZone.StandardDate.Milliseconds);
        } 


        //
        // ConvertUtcToTimeZone - 
        //
        // Helper function that converts a dateTime from UTC into the destinationTimeZone 
        // 
        // * returns DateTime.MaxValue when the converted value is too large
        // * returns DateTime.MinValue when the converted value is too small 
        //
        static private DateTime ConvertUtcToTimeZone(Int64 ticks, TimeZoneInfo destinationTimeZone, out Boolean isAmbiguousLocalDst) {
            DateTime utcConverted;
            DateTime localConverted; 

            // utcConverted is used to calculate the UTC offset in the destinationTimeZone 
            if (ticks > DateTime.MaxValue.Ticks) { 
                utcConverted = DateTime.MaxValue;
            } 
            else if (ticks < DateTime.MinValue.Ticks) {
                utcConverted = DateTime.MinValue;
            }
            else { 
                utcConverted = new DateTime(ticks);
            } 
 
            // verify the time is between MinValue and MaxValue in the new time zone
            TimeSpan offset = GetUtcOffsetFromUtc(utcConverted, destinationTimeZone, out isAmbiguousLocalDst); 
            ticks += offset.Ticks;

            if (ticks > DateTime.MaxValue.Ticks) {
                localConverted = DateTime.MaxValue; 
            }
            else if (ticks < DateTime.MinValue.Ticks) { 
                localConverted = DateTime.MinValue; 
            }
            else { 
                localConverted = new DateTime(ticks);
            }
            return localConverted;
        } 

 
        // 
        // CreateAdjustmentRuleFromTimeZoneInformation-
        // 
        // Converts a Win32Native.RegistryTimeZoneInformation (REG_TZI_FORMAT struct) to an AdjustmentRule
        //
        [System.Security.SecurityCritical]  // auto-generated
        static private AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(Win32Native.RegistryTimeZoneInformation timeZoneInformation, DateTime startDate, DateTime endDate) { 
            AdjustmentRule rule;
            bool supportsDst = (timeZoneInformation.StandardDate.Month != 0); 
 
            if (!supportsDst) {
                return null; 
            }

            //
            // Create an AdjustmentRule with TransitionTime objects 
            //
            TransitionTime daylightTransitionStart; 
            if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, true /* start date */)) { 
                return null;
            } 

            TransitionTime daylightTransitionEnd;
            if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, false /* end date */)) {
                return null; 
            }
 
            if (daylightTransitionStart.Equals(daylightTransitionEnd)) { 
                // this happens when the time zone does support DST but the OS has DST disabled
                return null; 
            }

            rule = AdjustmentRule.CreateAdjustmentRule(
                startDate, 
                endDate,
                new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), 
                (TransitionTime)daylightTransitionStart, 
                (TransitionTime)daylightTransitionEnd);
 
            return rule;
        }

 
#if FEATURE_WIN32_REGISTRY
        // 
        // FindIdFromTimeZoneInformation - 
        //
        // Helper function that searches the registry for a time zone entry 
        // that matches the TimeZoneInformation struct
        //
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        // @
        static private String FindIdFromTimeZoneInformation(Win32Native.TimeZoneInformation timeZone, out Boolean dstDisabled) { 
            dstDisabled = false; 

            try { 
                PermissionSet permSet = new PermissionSet(PermissionState.None);
                permSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, c_timeZonesRegistryHivePermissionList));
                permSet.Assert();
 
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(
                                  c_timeZonesRegistryHive, 
#if FEATURE_MACL 
                                  RegistryKeyPermissionCheck.Default,
                                  System.Security.AccessControl.RegistryRights.ReadKey 
#else
                                  false
#endif
                                  )) { 

                    if (key == null) { 
                        return null; 
                    }
                    foreach (string keyName in key.GetSubKeyNames()) { 
                        if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled)) {
                            return keyName;
                        }
                    } 
                }
            } 
            finally { 
                PermissionSet.RevertAssert();
            } 
            return null;
        }
#endif // FEATURE_WIN32_REGISTRY
 

        // 
        // GetDaylightTime - 
        //
        // Helper function that returns a DaylightTime from a year and AdjustmentRule 
        //
        static private DaylightTime GetDaylightTime(Int32 year, AdjustmentRule rule) {
            TimeSpan delta = rule.DaylightDelta;
            DateTime startTime = TransitionTimeToDateTime(year, rule.DaylightTransitionStart); 
            DateTime endTime = TransitionTimeToDateTime(year, rule.DaylightTransitionEnd);
            return new DaylightTime(startTime, endTime, delta); 
        } 

 

        //
        // GetIsDaylightSavings -
        // 
        // Helper function that checks if a given dateTime is in Daylight Saving Time (DST)
        // This function assumes the dateTime and AdjustmentRule are both in the same time zone 
        // 
        static private Boolean GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTime daylightTime, TimeZoneInfoOptions flags) {
            if (rule == null) { 
                return false;
            }

            DateTime startTime; 
            DateTime endTime;
 
            if (time.Kind == DateTimeKind.Local) { 
                // startTime and endTime represent the period from either the start of DST to the end and ***includes*** the
                // potentially overlapped times 
                startTime = daylightTime.Start + daylightTime.Delta;
                endTime = daylightTime.End;
            }
            else { 
                // startTime and endTime represent the period from either the start of DST to the end and
                // ***does not include*** the potentially overlapped times 
                // 
                //         -=-=-=-=-=- Pacific Standard Time -=-=-=-=-=-=-
                //    April 2, 2006                            October 29, 2006 
                // 2AM            3AM                        1AM              2AM
                // |      +1 hr     |                        |       -1 hr      |
                // |  |                        |  |
                //                  [========== DST ========>) 
                //
                //        -=-=-=-=-=- Some Weird Time Zone -=-=-=-=-=-=- 
                //    April 2, 2006                          October 29, 2006 
                // 1AM              2AM                    2AM              3AM
                // |      -1 hr       |                      |       +1 hr      | 
                // |  |                      |    |
                //                    [======== DST ========>)
                //
                Boolean invalidAtStart = rule.DaylightDelta > TimeSpan.Zero; 
                startTime = daylightTime.Start + (invalidAtStart ? rule.DaylightDelta : TimeSpan.Zero); /* */
                endTime = daylightTime.End + (invalidAtStart ? -rule.DaylightDelta : TimeSpan.Zero); 
            } 

            Boolean isDst = CheckIsDst(startTime, time, endTime); 

            // If this date was previously converted from a UTC date and we were able to detect that the local
            // DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity.
            if (isDst && time.Kind == DateTimeKind.Local) { 
                // For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the
                // clock back. It is theoretically possible to have a positive delta, (which would really be daylight 
                // reduction time), where you would have to wind the clock back in the begnning. 
                if (GetIsAmbiguousTime(time, rule, daylightTime)) {
                    isDst = time.IsAmbiguousDaylightSavingTime(); 
                }
            }

            return isDst; 
        }
 
 
        //
        // GetIsDaylightSavingsFromUtc - 
        //
        // Helper function that checks if a given dateTime is in Daylight Saving Time (DST)
        // This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone
        // 
        static private Boolean GetIsDaylightSavingsFromUtc(DateTime time, Int32 Year, TimeSpan utc, AdjustmentRule rule, out Boolean isAmbiguousLocalDst) {
            isAmbiguousLocalDst = false; 
 
            if (rule == null) {
                return false; 
            }

            // Get the daylight changes for the year of the specified time.
            TimeSpan offset = utc; /* */ 
            DaylightTime daylightTime = GetDaylightTime(Year, rule);
 
            // The start and end times represent the range of universal times that are in DST for that year. 
            // Within that there is an ambiguous hour, usually right at the end, but at the beginning in
            // the unusual case of a negative daylight savings delta. 
            DateTime startTime = daylightTime.Start - offset;
            DateTime endTime = daylightTime.End - offset - rule.DaylightDelta; /* */
            DateTime ambiguousStart;
            DateTime ambiguousEnd; 
            if (daylightTime.Delta.Ticks > 0) {
                ambiguousStart = endTime - daylightTime.Delta; 
                ambiguousEnd = endTime; 
            } else {
                ambiguousStart = startTime; 
                ambiguousEnd = startTime - daylightTime.Delta;
            }

            Boolean isDst = CheckIsDst(startTime, time, endTime); 

            // See if the resulting local time becomes ambiguous. This must be captured here or the 
            // DateTime will not be able to round-trip back to UTC accurately. 
            if (isDst) {
                isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); 

                if (!isAmbiguousLocalDst && ambiguousStart.Year != ambiguousEnd.Year) {
                    // there exists an extreme corner case where the start or end period is on a year boundary and
                    // because of this the comparison above might have been performed for a year-early or a year-later 
                    // than it should have been.
                    DateTime ambiguousStartModified; 
                    DateTime ambiguousEndModified; 
                    try {
                        ambiguousStartModified = ambiguousStart.AddYears(1); 
                        ambiguousEndModified   = ambiguousEnd.AddYears(1);
                        isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd);
                    }
                    catch (ArgumentOutOfRangeException) {} 

                    if (!isAmbiguousLocalDst) { 
                        try { 
                            ambiguousStartModified = ambiguousStart.AddYears(-1);
                            ambiguousEndModified   = ambiguousEnd.AddYears(-1); 
                            isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd);
                        }
                        catch (ArgumentOutOfRangeException) {}
                    } 

                } 
            } 

            return isDst; 
        }


        static private Boolean CheckIsDst(DateTime startTime, DateTime time, DateTime endTime) { 
            Boolean isDst;
 
            if (startTime.Year != endTime.Year) { 
                endTime = endTime.AddYears(startTime.Year - endTime.Year);
            } 
            if (startTime.Year != time.Year) {
                time = time.AddYears(startTime.Year - time.Year);
            }
 
            if (startTime > endTime) {
                // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. 
                // Note, the summer in the southern hemisphere begins late in the year. 
                isDst = (time < endTime || time >= startTime);
            } 
            else {
                // In northern hemisphere, the daylight saving time starts in the middle of the year.
                isDst = (time >= startTime && time < endTime);
            } 
            return isDst;
        } 
 

        // 
        // GetIsAmbiguousTime(DateTime dateTime, AdjustmentRule rule, DaylightTime daylightTime) -
        //
        // returns true when the dateTime falls into an ambiguous time range.
        // For example, in Pacific Standard Time on Sunday, October 29, 2006 time jumps from 
        // 2AM to 1AM.  This means the timeline on Sunday proceeds as follows:
        // 12AM ... [1AM ... 1:59:59AM -> 1AM ... 1:59:59AM] 2AM ... 3AM ... 
        // 
        // In this example, any DateTime values that fall into the [1AM - 1:59:59AM] range
        // are ambiguous; as it is unclear if these times are in Daylight Saving Time. 
        //
        static private Boolean GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTime daylightTime) {
            Boolean isAmbiguous = false;
            if (rule == null || rule.DaylightDelta == TimeSpan.Zero) { 
                return isAmbiguous;
            } 
 
            DateTime startAmbiguousTime;
            DateTime endAmbiguousTime; 

            // if at DST start we transition forward in time then there is an ambiguous time range at the DST end
            if (rule.DaylightDelta > TimeSpan.Zero) {
                startAmbiguousTime = daylightTime.End; 
                endAmbiguousTime = daylightTime.End - rule.DaylightDelta; /* */
            } 
            else { 
                startAmbiguousTime = daylightTime.Start;
                endAmbiguousTime = daylightTime.Start + rule.DaylightDelta; /* */ 
            }

            isAmbiguous = (time >= endAmbiguousTime && time < startAmbiguousTime);
 
            if (!isAmbiguous && startAmbiguousTime.Year != endAmbiguousTime.Year) {
                // there exists an extreme corner case where the start or end period is on a year boundary and 
                // because of this the comparison above might have been performed for a year-early or a year-later 
                // than it should have been.
                DateTime startModifiedAmbiguousTime; 
                DateTime endModifiedAmbiguousTime;
                try {
                    startModifiedAmbiguousTime = startAmbiguousTime.AddYears(1);
                    endModifiedAmbiguousTime   = endAmbiguousTime.AddYears(1); 
                    isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime);
                } 
                catch (ArgumentOutOfRangeException) {} 

                if (!isAmbiguous) { 
                    try {
                        startModifiedAmbiguousTime = startAmbiguousTime.AddYears(-1);
                        endModifiedAmbiguousTime  = endAmbiguousTime.AddYears(-1);
                        isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); 
                    }
                    catch (ArgumentOutOfRangeException) {} 
                } 
            }
            return isAmbiguous; 
        }


 
        //
        // GetIsInvalidTime - 
        // 
        // Helper function that checks if a given DateTime is in an invalid time ("time hole")
        // A "time hole" occurs at a DST transition point when time jumps forward; 
        // For example, in Pacific Standard Time on Sunday, April 2, 2006 time jumps from
        // 1:59:59.9999999 to 3AM.  The time range 2AM to 2:59:59.9999999AM is the "time hole".
        // A "time hole" is not limited to only occurring at the start of DST, and may occur at
        // the end of DST as well. 
        //
        static private Boolean GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTime daylightTime) { 
            Boolean isInvalid = false; 
            if (rule == null || rule.DaylightDelta == TimeSpan.Zero) {
                return isInvalid; 
            }

            DateTime startInvalidTime;
            DateTime endInvalidTime; 

            // if at DST start we transition forward in time then there is an ambiguous time range at the DST end 
            if (rule.DaylightDelta < TimeSpan.Zero) { 
                startInvalidTime = daylightTime.End;
                endInvalidTime = daylightTime.End - rule.DaylightDelta; /* */ 
            }
            else {
                startInvalidTime = daylightTime.Start;
                endInvalidTime = daylightTime.Start + rule.DaylightDelta; /* */ 
            }
 
            isInvalid = (time >= startInvalidTime && time < endInvalidTime); 

            if (!isInvalid && startInvalidTime.Year != endInvalidTime.Year) { 
                // there exists an extreme corner case where the start or end period is on a year boundary and
                // because of this the comparison above might have been performed for a year-early or a year-later
                // than it should have been.
                DateTime startModifiedInvalidTime; 
                DateTime endModifiedInvalidTime;
                try { 
                    startModifiedInvalidTime = startInvalidTime.AddYears(1); 
                    endModifiedInvalidTime   = endInvalidTime.AddYears(1);
                    isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); 
                }
                catch (ArgumentOutOfRangeException) {}

                if (!isInvalid) { 
                    try {
                        startModifiedInvalidTime = startInvalidTime.AddYears(-1); 
                        endModifiedInvalidTime  = endInvalidTime.AddYears(-1); 
                        isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime);
                    } 
                    catch (ArgumentOutOfRangeException) {}
                }
            }
            return isInvalid; 
        }
 
 

        // 
        // GetLocalTimeZone -
        //
        // Helper function for retrieving the local system time zone.
        // 
        // returns a new TimeZoneInfo instance
        // 
        // may throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException 
        //
        // 

        [System.Security.SecuritySafeCritical]  // auto-generated
        static private TimeZoneInfo GetLocalTimeZone() {
 

#if FEATURE_WIN32_REGISTRY 
            String id = null; 

            if (c_VistaOrNewer) { 
                //
                // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id"
                //
                Win32Native.DynamicTimeZoneInformation dynamicTimeZoneInformation = 
                    new Win32Native.DynamicTimeZoneInformation();
 
                // call kernel32!GetDynamicTimeZoneInformation... 
                long result = UnsafeNativeMethods.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation);
                if (result == Win32Native.TIME_ZONE_ID_INVALID) { 
                    // return a dummy entry
                    return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);
                }
 
                Win32Native.TimeZoneInformation timeZoneInformation =
                    new Win32Native.TimeZoneInformation(dynamicTimeZoneInformation); 
 
                // DynamicDaylightTimeDisabled:
                // Indicates whether dynamic daylight saving time is disabled. Setting this member to TRUE disables 
                // dynamic daylight saving time, causing the system to use a fixed set of transition dates.
                Boolean dynamicDstDisabled = dynamicTimeZoneInformation.DynamicDaylightTimeDisabled;
                if (dynamicDstDisabled) {
                    return GetLocalTimeZoneFromWin32Data(timeZoneInformation, false); 
                }
 
                // check to see if we can use the key name returned from the API call 
                if (!String.IsNullOrEmpty(dynamicTimeZoneInformation.TimeZoneKeyName)) {
                    TimeZoneInfo zone; 
                    Exception ex;


                    if (TryGetTimeZone(dynamicTimeZoneInformation.TimeZoneKeyName, false, out zone, out ex) == TimeZoneInfoResult.Success) { 
                        // successfully loaded the time zone from the registry
                        return zone; 
                    } 
                }
 
                // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves
                Boolean dstDisabled;
                id = FindIdFromTimeZoneInformation(timeZoneInformation, out dstDisabled);
 
                if (id != null) {
                    TimeZoneInfo zone; 
                    Exception ex; 
                    if (TryGetTimeZone(id, false, out zone, out ex) == TimeZoneInfoResult.Success) {
                        // successfully loaded the time zone from the registry 
                        return zone;
                    }
                }
 
                // We could not find the data in the registry.  Fall back to using
                // the data from the Win32 API 
                return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); 
            }
            else { 
                //
                // Fall back to calling "kernel32!GetTimeZoneInformation"
                //
                Win32Native.TimeZoneInformation timeZoneInformation = new Win32Native.TimeZoneInformation(); 

                // call kernel32!GetTimeZoneInformation... 
                long result = UnsafeNativeMethods.GetTimeZoneInformation(out timeZoneInformation); 
                if (result == Win32Native.TIME_ZONE_ID_INVALID) {
                    // return a dummy entry 
                    return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);
                }

                // this legacy win32 api does not return the key name - 
                // we must search for the entry ourselves
                Boolean dstDisabled; 
                id = FindIdFromTimeZoneInformation(timeZoneInformation, out dstDisabled); 
                if (id != null) {
                    TimeZoneInfo zone; 
                    Exception ex;
                    if (TryGetTimeZone(id, dstDisabled, out zone, out ex) == TimeZoneInfoResult.Success) {
                        // successfully loaded the time zone from the registry
                        return zone; 
                    }
                } 
 
                //
                // We could not find the data in the registry.  Fall back to using 
                // the data from the Win32 API
                //
                return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled);
            } 

#else // FEATURE_WIN32_REGISTRY 
            // Without Registry support, just create a dummy TZ for now 
            return GetLocalTimeZoneFromTzFile();
#endif // FEATURE_WIN32_REGISTRY 
        }


#if !FEATURE_WIN32_REGISTRY 
        //
        // GetLocalTimeZoneFromTzFile - 
        // 
        // Helper function used by 'GetLocalTimeZone()' - this function wraps the call
        // for loading time zone data from computers without Registry support. 
        //
        // The GetLocalTzFile() call returns a Byte[] containing the compiled tzfile.
        //
// 
[System.Security.SecurityCritical]
        static private TimeZoneInfo GetLocalTimeZoneFromTzFile() { 
            Byte[] rawData = GetLocalTzFile(); 

            if (rawData != null) { 
                try {
                    return new TimeZoneInfo(rawData, false); // create a TimeZoneInfo instance from the TZif data w/ DST support
                }
                catch (ArgumentException) {} 
                catch (InvalidTimeZoneException e) {}
                try { 
                    return new TimeZoneInfo(rawData, true); // create a TimeZoneInfo instance from the TZif data w/o DST support 
                }
                catch (ArgumentException) {} 
                catch (InvalidTimeZoneException) {}
             }
            // the data returned from the PAL is completely bogus; return a dummy entry
            return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId); 
        }
#endif // !FEATURE_WIN32_REGISTRY 
 

        // 
        // GetLocalTimeZoneFromWin32Data -
        //
        // Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of
        // try/catch logic for handling the TimeZoneInfo private constructor that takes 
        // a Win32Native.TimeZoneInformation structure.
        // 
        [System.Security.SecurityCritical]  // auto-generated 
        static private TimeZoneInfo GetLocalTimeZoneFromWin32Data(Win32Native.TimeZoneInformation timeZoneInformation, Boolean dstDisabled) {
            // first try to create the TimeZoneInfo with the original 'dstDisabled' flag 
            try {
                return new TimeZoneInfo(timeZoneInformation, dstDisabled);
            }
            catch (ArgumentException) {} 
            catch (InvalidTimeZoneException) {}
 
            // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort 
            if (!dstDisabled) {
                try { 
                    return new TimeZoneInfo(timeZoneInformation, true);
                }
                catch (ArgumentException) {}
                catch (InvalidTimeZoneException) {} 
            }
 
            // the data returned from Windows is completely bogus; return a dummy entry 
            return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);
        } 


#if FEATURE_WIN32_REGISTRY
        // 
        // GetTimeZone -
        // 
        // Helper function for retrieving a TimeZoneInfo object by . 
        // This function wraps the logic necessary to keep the private
        // SystemTimeZones cache in working order 
        //
        // This function will either return a valid TimeZoneInfo instance or
        // it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'.
        // 
        static private TimeZoneInfo GetTimeZone(string id) {
            if (id == null) { 
                throw new ArgumentNullException("id"); 
            }
            else if (id.Length == 0 || id.Length > c_maxKeyLength || id.Contains("\0")) { 
                throw new TimeZoneNotFoundException(Environment.GetResourceString("TimeZoneNotFound_MissingRegistryData", id));
            }

            TimeZoneInfo value; 
            Exception e;
            TimeZoneInfoResult result = TryGetTimeZone(id, false, out value, out e); 
 
            if (result == TimeZoneInfoResult.Success) {
                return value; 
            }
            else if (result == TimeZoneInfoResult.InvalidTimeZoneException) {
                throw new InvalidTimeZoneException(Environment.GetResourceString("InvalidTimeZone_InvalidRegistryData", id), e);
            } 
            else if (result == TimeZoneInfoResult.SecurityException) {
                throw new SecurityException(Environment.GetResourceString("Security_CannotReadRegistryData", id), e); 
            } 
            else {
                throw new TimeZoneNotFoundException(Environment.GetResourceString("TimeZoneNotFound_MissingRegistryData", id), e); 
            }
        }
#endif // FEATURE_WIN32_REGISTRY
 

        // 
        // GetUtcOffset - 
        //
        // Helper function that calculates the UTC offset for a dateTime in a timeZone. 
        // This function assumes that the dateTime is already converted into the timeZone.
        //
        static private TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags) {
            TimeSpan baseOffset = zone.BaseUtcOffset; 
            AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time);
 
            if (rule != null) { 
                DaylightTime daylightTime = GetDaylightTime(time.Year, rule);
                Boolean isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); 
                baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* */);
            }

            return baseOffset; 
        }
 
 
        //
        // GetUtcOffsetFromUtc - 
        //
        // Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone.
        // This function assumes that the dateTime is represented in UTC and has *not*
        // already been converted into the timeZone. 
        //
        static private TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone) { 
            Boolean isDaylightSavings; 
            return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings);
        } 

        static private TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out Boolean isDaylightSavings) {
            Boolean isAmbiguousLocalDst;
            return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings, out isAmbiguousLocalDst); 
        }
 
        // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone 
        static internal TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out Boolean isAmbiguousLocalDst) {
            Boolean isDaylightSavings = false; 
#if FEATURE_WIN32_REGISTRY
            isAmbiguousLocalDst = false;
            TimeSpan baseOffset;
            OffsetAndRule match = GetOneYearLocalFromUtc(time.Year); 
            baseOffset = match.offset;
 
            if (match.rule != null) { 
                isDaylightSavings = GetIsDaylightSavingsFromUtc(time, time.Year, match.offset, match.rule, out isAmbiguousLocalDst);
                baseOffset += (isDaylightSavings ? match.rule.DaylightDelta : TimeSpan.Zero /* */); 
            }
            return baseOffset;
#else
            // Use the standard code path for the Macintosh since there isn't a faster way of handling current-year-only time zones 
            return GetUtcOffsetFromUtc(time, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst);
#endif // FEATURE_WIN32_REGISTRY 
        } 

#if FEATURE_WIN32_REGISTRY 
        [System.Security.SecuritySafeCritical]
        static private OffsetAndRule GetOneYearLocalFromLocal(int year) {
            if (s_oneYearLocalFromLocal == null || s_oneYearLocalFromLocal.year != year) {
                TimeZoneInfo currentYear = GetCurrentOneYearLocal(); 
                AdjustmentRule rule = currentYear.m_adjustmentRules == null ? null : currentYear.m_adjustmentRules[0];
                s_oneYearLocalFromLocal = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); 
            } 
            return s_oneYearLocalFromLocal;
        } 

        [System.Security.SecuritySafeCritical]
        static private OffsetAndRule GetOneYearLocalFromUtc(int year) {
            if (s_oneYearLocalFromUtc == null || s_oneYearLocalFromUtc.year != year) { 
                TimeZoneInfo currentYear = GetCurrentOneYearLocal();
                AdjustmentRule rule = currentYear.m_adjustmentRules == null ? null : currentYear.m_adjustmentRules[0]; 
                s_oneYearLocalFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); 
            }
            return s_oneYearLocalFromUtc; 
        }

        [System.Security.SecurityCritical]
        static private TimeZoneInfo GetCurrentOneYearLocal() { 
            // load the data from the OS
            TimeZoneInfo match; 
 
            Win32Native.TimeZoneInformation timeZoneInformation = new Win32Native.TimeZoneInformation();
            long result = UnsafeNativeMethods.GetTimeZoneInformation(out timeZoneInformation); 
            if (result == Win32Native.TIME_ZONE_ID_INVALID)
                match = CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);
            else
                match = GetLocalTimeZoneFromWin32Data(timeZoneInformation, false); 
            return match;
        } 
#endif // FEATURE_WIN32_REGISTRY 

        static internal TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out Boolean isDaylightSavings, out Boolean isAmbiguousLocalDst) { 
            isDaylightSavings = false;
            isAmbiguousLocalDst = false;
            TimeSpan baseOffset = zone.BaseUtcOffset;
            Int32 year; 
            AdjustmentRule rule;
 
            if (time > new DateTime(9999, 12, 31)) { 
                rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue);
                year = 9999; 
            }
            else if (time < new DateTime(1, 1, 2)) {
                rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue);
                year = 1; 
            }
            else { 
                DateTime targetTime = time + baseOffset; 
                year = time.Year;
                rule = zone.GetAdjustmentRuleForTime(targetTime); 
            }

            if (rule != null) {
                isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone.m_baseUtcOffset, rule, out isAmbiguousLocalDst); 
                baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* */);
            } 
 
            return baseOffset;
        } 


        //
        // TransitionTimeFromTimeZoneInformation - 
        //
        // Converts a Win32Native.RegistryTimeZoneInformation (REG_TZI_FORMAT struct) to a TransitionTime 
        // 
        // * when the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read
        // * when the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read 
        //
        [System.Security.SecurityCritical]  // auto-generated
        static private bool TransitionTimeFromTimeZoneInformation(Win32Native.RegistryTimeZoneInformation timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) {
            // 
            // SYSTEMTIME -
            // 
            // If the time zone does not support daylight saving time or if the caller needs 
            // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure
            // must be zero. If this date is specified, the DaylightDate value in the 
            // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system
            // assumes the time zone data is invalid and no changes will be applied.
            //
            bool supportsDst = (timeZoneInformation.StandardDate.Month != 0); 

            if (!supportsDst) { 
                transitionTime = default(TransitionTime); 
                return false;
            } 

            //
            // SYSTEMTIME -
            // 
            // * FixedDateRule -
            //   If the Year member is not zero, the transition date is absolute; it will only occur one time 
            // 
            // * FloatingDateRule -
            //   To select the correct day in the month, set the Year member to zero, the Hour and Minute 
            //   members to the transition time, the DayOfWeek member to the appropriate weekday, and the
            //   Day member to indicate the occurence of the day of the week within the month (first through fifth).
            //
            //   Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: 
            //   Hour      = 2,
            //   Month     = 4, 
            //   DayOfWeek = 0, 
            //   Day       = 1.
            // 
            //   Specify 2:00a.m. on the last Thursday in October as follows:
            //   Hour      = 2,
            //   Month     = 10,
            //   DayOfWeek = 4, 
            //   Day       = 5.
            // 
            if (readStartDate) { 
                 //
                 // read the "daylightTransitionStart" 
                 //
                 if (timeZoneInformation.DaylightDate.Year == 0) {
                    transitionTime = TransitionTime.CreateFloatingDateRule(
                                     new DateTime(1,    /* year  */ 
                                                  1,    /* month */
                                                  1,    /* day   */ 
                                                  timeZoneInformation.DaylightDate.Hour, 
                                                  timeZoneInformation.DaylightDate.Minute,
                                                  timeZoneInformation.DaylightDate.Second, 
                                                  timeZoneInformation.DaylightDate.Milliseconds),
                                     timeZoneInformation.DaylightDate.Month,
                                     timeZoneInformation.DaylightDate.Day,   /* Week 1-5 */
                                     (DayOfWeek) timeZoneInformation.DaylightDate.DayOfWeek); 
                }
                else { 
                    transitionTime = TransitionTime.CreateFixedDateRule( 
                                     new DateTime(1,    /* year  */
                                                  1,    /* month */ 
                                                  1,    /* day   */
                                                  timeZoneInformation.DaylightDate.Hour,
                                                  timeZoneInformation.DaylightDate.Minute,
                                                  timeZoneInformation.DaylightDate.Second, 
                                                  timeZoneInformation.DaylightDate.Milliseconds),
                                     timeZoneInformation.DaylightDate.Month, 
                                     timeZoneInformation.DaylightDate.Day); 
                }
            } 
            else {
                //
                // read the "daylightTransitionEnd"
                // 
                if (timeZoneInformation.StandardDate.Year == 0) {
                    transitionTime = TransitionTime.CreateFloatingDateRule( 
                                     new DateTime(1,    /* year  */ 
                                                  1,    /* month */
                                                  1,    /* day   */ 
                                                  timeZoneInformation.StandardDate.Hour,
                                                  timeZoneInformation.StandardDate.Minute,
                                                  timeZoneInformation.StandardDate.Second,
                                                  timeZoneInformation.StandardDate.Milliseconds), 
                                     timeZoneInformation.StandardDate.Month,
                                     timeZoneInformation.StandardDate.Day,   /* Week 1-5 */ 
                                     (DayOfWeek) timeZoneInformation.StandardDate.DayOfWeek); 
                }
                else { 
                    transitionTime = TransitionTime.CreateFixedDateRule(
                                     new DateTime(1,    /* year  */
                                                  1,    /* month */
                                                  1,    /* day   */ 
                                                  timeZoneInformation.StandardDate.Hour,
                                                  timeZoneInformation.StandardDate.Minute, 
                                                  timeZoneInformation.StandardDate.Second, 
                                                  timeZoneInformation.StandardDate.Milliseconds),
                                     timeZoneInformation.StandardDate.Month, 
                                     timeZoneInformation.StandardDate.Day);
                }
            }
 
            return true;
        } 
 
        //
        // TransitionTimeToDateTime - 
        //
        // Helper function that converts a year and TransitionTime into a DateTime
        //
        static private DateTime TransitionTimeToDateTime(Int32 year, TransitionTime transitionTime) { 
            DateTime value;
            DateTime timeOfDay = transitionTime.TimeOfDay; 
 
            if (transitionTime.IsFixedDateRule) {
                // create a DateTime from the passed in year and the properties on the transitionTime 

                // if the day is out of range for the month then use the last day of the month
                Int32 day = DateTime.DaysInMonth(year, transitionTime.Month);
 
                value = new DateTime(year, transitionTime.Month, (day < transitionTime.Day) ? day : transitionTime.Day,
                            timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); 
            } 
            else {
                if (transitionTime.Week <= 4) { 
                    //
                    // Get the (transitionTime.Week)th Sunday.
                    //
                    value = new DateTime(year, transitionTime.Month, 1, 
                            timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond);
 
                    int dayOfWeek = (int)value.DayOfWeek; 
                    int delta = (int)transitionTime.DayOfWeek - dayOfWeek;
                    if (delta < 0) { 
                        delta += 7;
                    }
                    delta += 7 * (transitionTime.Week - 1);
 
                    if (delta > 0) {
                        value = value.AddDays(delta); 
                    } 
                }
                else { 
                    //
                    // If TransitionWeek is greater than 4, we will get the last week.
                    //
                    Int32 daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); 
                    value = new DateTime(year, transitionTime.Month, daysInMonth,
                            timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); 
 
                    // This is the day of week for the last day of the month.
                    int dayOfWeek = (int)value.DayOfWeek; 
                    int delta = dayOfWeek - (int)transitionTime.DayOfWeek;
                    if (delta < 0) {
                        delta += 7;
                    } 

                    if (delta > 0) { 
                        value = value.AddDays(-delta); 
                    }
                } 
            }
            return value;
        }
 
#if FEATURE_WIN32_REGISTRY
        // 
        // TryCreateAdjustmentRules - 
        //
        // Helper function that takes 
        //  1. a string representing a  registry key name
        //  2. a RegistryTimeZoneInformation struct containing the default rule
        //  3. an AdjustmentRule[] out-parameter
        // 
        // returns
        //     TimeZoneInfoResult.InvalidTimeZoneException, 
        //     TimeZoneInfoResult.TimeZoneNotFoundException, 
        //     TimeZoneInfoResult.Success
        // 
        // Optional, Dynamic Time Zone Registry Data
        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        //
        // HKLM 
        //     Software
        //         Microsoft 
        //             Windows NT 
        //                 CurrentVersion
        //                     Time Zones 
        //                         
        //                             Dynamic DST
        // * "FirstEntry" REG_DWORD "1980"
        //                           First year in the table. If the current year is less than this value, 
        //                           this entry will be used for DST boundaries
        // * "LastEntry"  REG_DWORD "2038" 
        //                           Last year in the table. If the current year is greater than this value, 
        //                           this entry will be used for DST boundaries"
        // * ""    REG_BINARY REG_TZI_FORMAT 
        //                       See Win32Native.RegistryTimeZoneInformation
        // * ""    REG_BINARY REG_TZI_FORMAT
        //                       See Win32Native.RegistryTimeZoneInformation
        // * ""    REG_BINARY REG_TZI_FORMAT 
        //                       See Win32Native.RegistryTimeZoneInformation
        // 
        // This method expects that its caller has already Asserted RegistryPermission.Read 
        //
        [System.Security.SecurityCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)]
        // @
        static private bool TryCreateAdjustmentRules(string id, Win32Native.RegistryTimeZoneInformation defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e) {
            e = null; 

            try { 
                using (RegistryKey dynamicKey = Registry.LocalMachine.OpenSubKey( 
                                   String.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\Dynamic DST",
                                       c_timeZonesRegistryHive, id), 
#if FEATURE_MACL
                                   RegistryKeyPermissionCheck.Default,
                                   System.Security.AccessControl.RegistryRights.ReadKey
#else 
                                   false
#endif 
                                   )) { 
                    if (dynamicKey == null) {
                        AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation( 
                                              defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date);

                        if (rule == null) {
                            rules = null; 
                        }
                        else { 
                            rules = new AdjustmentRule[1]; 
                            rules[0] = rule;
                        } 

                        return true;
                    }
 
                    //
                    // loop over all of the "\Dynamic DST" hive entries 
                    // 
                    // read FirstEntry  {MinValue      - (year1, 12, 31)}
                    // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)} 
                    // read LastEntry   {(yearN, 1, 1) - MaxValue       }

                    // read the FirstEntry and LastEntry key values (ex: "1980", "2038")
                    Int32 first = (Int32)dynamicKey.GetValue(c_firstEntryValue, -1, RegistryValueOptions.None); 
                    Int32 last = (Int32)dynamicKey.GetValue(c_lastEntryValue, -1, RegistryValueOptions.None);
 
                    if (first == -1 || last == -1 || first > last) { 
                        rules = null;
                        return false; 
                    }

                    // read the first year entry
                    Win32Native.RegistryTimeZoneInformation dtzi; 
                    Byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[];
                    if (regValue == null || regValue.Length != c_regByteLength) { 
                        rules = null; 
                        return false;
                    } 
                    dtzi = new Win32Native.RegistryTimeZoneInformation(regValue);

                    if (first == last) {
                        // there is just 1 dynamic rule for this time zone. 
                        AdjustmentRule rule =  CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date);
 
                        if (rule == null) { 
                            rules = null;
                        } 
                        else {
                            rules = new AdjustmentRule[1];
                            rules[0] = rule;
                        } 

                        return true; 
                    } 

                    List rulesList = new List(1); 

                     // there are more than 1 dynamic rules for this time zone.
                    AdjustmentRule firstRule = CreateAdjustmentRuleFromTimeZoneInformation(
                                              dtzi, 
                                              DateTime.MinValue.Date,        // MinValue
                                              new DateTime(first, 12, 31)); // December 31,  
                    if (firstRule != null) { 
                        rulesList.Add(firstRule);
                    } 

                    // read the middle year entries
                    for (Int32 i = first + 1; i < last; i++) {
                        regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[]; 
                        if (regValue == null || regValue.Length != c_regByteLength) {
                            rules = null; 
                            return false; 
                        }
                        dtzi = new Win32Native.RegistryTimeZoneInformation(regValue); 
                        AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation(
                                                  dtzi,
                                                  new DateTime(i, 1, 1),    // January  01, 
                                                  new DateTime(i, 12, 31)); // December 31,  
                        if (middleRule != null) {
                            rulesList.Add(middleRule); 
                        } 
                    }
                    // read the last year entry 
                    regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[];
                    dtzi = new Win32Native.RegistryTimeZoneInformation(regValue);
                    if (regValue == null || regValue.Length != c_regByteLength) {
                        rules = null; 
                        return false;
                    } 
                    AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation( 
                                              dtzi,
                                              new DateTime(last, 1, 1),    // January  01,  
                                              DateTime.MaxValue.Date);     // MaxValue
                    if (lastRule != null) {
                        rulesList.Add(lastRule);
                    } 

                    // convert the ArrayList to an AdjustmentRule array 
                    rules = rulesList.ToArray(); 
                    if (rules != null && rules.Length == 0) {
                        rules = null; 
                    }
                } // end of: using (RegistryKey dynamicKey...
            }
            catch (InvalidCastException ex) { 
                // one of the RegistryKey.GetValue calls could not be cast to an expected value type
                rules = null; 
                e = ex; 
                return false;
            } 
            catch (ArgumentOutOfRangeException ex) {
                rules = null;
                e = ex;
                return false; 
            }
            catch (ArgumentException ex) { 
                rules = null; 
                e = ex;
                return false; 
            }
            return true;
        }
#endif // FEATURE_WIN32_REGISTRY 

 
#if FEATURE_WIN32_REGISTRY 
        //
        // TryCompareStandardDate - 
        //
        // Helper function that compares the StandardBias and StandardDate portion a
        // TimeZoneInformation struct to a time zone registry entry
        // 
        [System.Security.SecurityCritical]  // auto-generated
        static private Boolean TryCompareStandardDate(Win32Native.TimeZoneInformation timeZone, Win32Native.RegistryTimeZoneInformation registryTimeZoneInfo) { 
            return timeZone.Bias                         == registryTimeZoneInfo.Bias 
                   && timeZone.StandardBias              == registryTimeZoneInfo.StandardBias
                   && timeZone.StandardDate.Year         == registryTimeZoneInfo.StandardDate.Year 
                   && timeZone.StandardDate.Month        == registryTimeZoneInfo.StandardDate.Month
                   && timeZone.StandardDate.DayOfWeek    == registryTimeZoneInfo.StandardDate.DayOfWeek
                   && timeZone.StandardDate.Day          == registryTimeZoneInfo.StandardDate.Day
                   && timeZone.StandardDate.Hour         == registryTimeZoneInfo.StandardDate.Hour 
                   && timeZone.StandardDate.Minute       == registryTimeZoneInfo.StandardDate.Minute
                   && timeZone.StandardDate.Second       == registryTimeZoneInfo.StandardDate.Second 
                   && timeZone.StandardDate.Milliseconds == registryTimeZoneInfo.StandardDate.Milliseconds; 
        }
#endif // FEATURE_WIN32_REGISTRY 


#if FEATURE_WIN32_REGISTRY
        // 
        // TryCompareTimeZoneInformationToRegistry -
        // 
        // Helper function that compares a TimeZoneInformation struct to a time zone registry entry 
        //
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [ResourceExposure(ResourceScope.None)]
        // @
        static private Boolean TryCompareTimeZoneInformationToRegistry(Win32Native.TimeZoneInformation timeZone, string id, out Boolean dstDisabled) {
 
            dstDisabled = false;
            try { 
                PermissionSet permSet = new PermissionSet(PermissionState.None); 
                permSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, c_timeZonesRegistryHivePermissionList));
                permSet.Assert(); 

                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(
                                  String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
                                      c_timeZonesRegistryHive, id), 
#if FEATURE_MACL
                                  RegistryKeyPermissionCheck.Default, 
                                  System.Security.AccessControl.RegistryRights.ReadKey 
#else
                                  false 
#endif
                                  )) {

                    if (key == null) { 
                        return false;
                    } 
 
                    Win32Native.RegistryTimeZoneInformation registryTimeZoneInfo;
                    Byte[] regValue = (Byte[])key.GetValue(c_timeZoneInfoValue, null, RegistryValueOptions.None) as Byte[]; 
                    if (regValue == null || regValue.Length != c_regByteLength) return false;
                    registryTimeZoneInfo = new Win32Native.RegistryTimeZoneInformation(regValue);

                    // 
                    // first compare the bias and standard date information between the data from the Win32 API
                    // and the data from the registry... 
                    // 
                    Boolean result = TryCompareStandardDate(timeZone, registryTimeZoneInfo);
 
                    if (!result) {
                        return false;
                    }
 
                    dstDisabled = CheckDaylightSavingTimeDisabledDownlevel();
 
                    result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) 
                             //
                             // since Daylight Saving Time is not "disabled", do a straight comparision between 
                             // the Win32 API data and the registry data ...
                             //
                             ||(   timeZone.DaylightBias              == registryTimeZoneInfo.DaylightBias
                                && timeZone.DaylightDate.Year         == registryTimeZoneInfo.DaylightDate.Year 
                                && timeZone.DaylightDate.Month        == registryTimeZoneInfo.DaylightDate.Month
                                && timeZone.DaylightDate.DayOfWeek    == registryTimeZoneInfo.DaylightDate.DayOfWeek 
                                && timeZone.DaylightDate.Day          == registryTimeZoneInfo.DaylightDate.Day 
                                && timeZone.DaylightDate.Hour         == registryTimeZoneInfo.DaylightDate.Hour
                                && timeZone.DaylightDate.Minute       == registryTimeZoneInfo.DaylightDate.Minute 
                                && timeZone.DaylightDate.Second       == registryTimeZoneInfo.DaylightDate.Second
                                && timeZone.DaylightDate.Milliseconds == registryTimeZoneInfo.DaylightDate.Milliseconds);

                    // Finally compare the "StandardName" string value... 
                    //
                    // we do not compare "DaylightName" as this TimeZoneInformation field may contain 
                    // either "StandardName" or "DaylightName" depending on the time of year and current machine settings 
                    //
                    if (result) { 
                        String registryStandardName = key.GetValue(c_standardValue, String.Empty, RegistryValueOptions.None) as String;
                        result = String.Compare(registryStandardName, timeZone.StandardName, StringComparison.Ordinal) == 0;
                    }
                    return result; 
                }
            } 
            finally { 
                PermissionSet.RevertAssert();
            } 
        }
#endif // FEATURE_WIN32_REGISTRY

 
#if FEATURE_WIN32_REGISTRY
        // 
        // TryGetLocalizedNameByMuiNativeResource - 
        //
        // Helper function for retrieving a localized string resource via MUI. 
        // The function expects a string in the form: "@resource.dll, -123"
        //
        // "resource.dll" is a language-neutral portable executable (LNPE) file in
        // the %windir%\system32 directory.  The OS is queried to find the best-fit 
        // localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui).
        // If a localized resource file exists, we LoadString resource ID "123" and 
        // return it to our caller. 
        //
        //  
        // 
        // 
        // 
        [System.Security.SecuritySafeCritical]  // auto-generated 
        [FileIOPermissionAttribute(SecurityAction.Assert, AllLocalFiles = FileIOPermissionAccess.PathDiscovery)]
        static private string TryGetLocalizedNameByMuiNativeResource(string resource) { 
            if (String.IsNullOrEmpty(resource)) { 
                return String.Empty;
            } 

            // parse "@tzres.dll, -100"
            //
            // filePath   = "C:\Windows\System32\tzres.dll" 
            // resourceId = -100
            // 
            string[] resources = resource.Split(new char[] {','}, StringSplitOptions.None); 
            if (resources.Length != 2) {
                return String.Empty; 
            }

            string filePath;
            int resourceId; 

            // get the path to Windows\System32 
            string system32 = Environment.GetFolderPath(Environment.SpecialFolder.System); 

            // trim the string "@tzres.dll" => "tzres.dll" 
            string tzresDll = resources[0].TrimStart(new char[] {'@'});

            try {
                filePath = Path.Combine(system32, tzresDll); 
            }
            catch (ArgumentException) { 
                //  there were probably illegal characters in the path 
                return String.Empty;
            } 

            if (!Int32.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) {
                return String.Empty;
            } 
            resourceId = -resourceId;
 
 
            try {
                StringBuilder fileMuiPath = new StringBuilder(Win32Native.MAX_PATH); 
                fileMuiPath.Length = Win32Native.MAX_PATH;
                int fileMuiPathLength = Win32Native.MAX_PATH;
                int languageLength = 0;
                Int64 enumerator = 0; 

                Boolean succeeded = UnsafeNativeMethods.GetFileMUIPath( 
                                        Win32Native.MUI_PREFERRED_UI_LANGUAGES, 
                                        filePath, null /* language */, ref languageLength,
                                        fileMuiPath, ref fileMuiPathLength, ref enumerator); 
                if (!succeeded) {
                    return String.Empty;
                }
                return TryGetLocalizedNameByNativeResource(fileMuiPath.ToString(), resourceId); 
            }
            catch (EntryPointNotFoundException) { 
                return String.Empty; 
            }
        } 
#endif // FEATURE_WIN32_REGISTRY


 
#if FEATURE_WIN32_REGISTRY
        // 
        // TryGetLocalizedNameByNativeResource - 
        //
        // Helper function for retrieving a localized string resource via a native resource DLL. 
        // The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll"
        //
        // "resource.dll" is a language-specific resource DLL.
        // If the localized resource DLL exists, LoadString(resource) is returned. 
        //
        [System.Security.SecuritySafeCritical]  // auto-generated 
        static private string TryGetLocalizedNameByNativeResource(string filePath, int resource) { 
            using (SafeLibraryHandle handle =
                       UnsafeNativeMethods.LoadLibraryEx(filePath, IntPtr.Zero, Win32Native.LOAD_LIBRARY_AS_DATAFILE)) { 

                if (!handle.IsInvalid) {
                    StringBuilder localizedResource = new StringBuilder(Win32Native.LOAD_STRING_MAX_LENGTH);
                    localizedResource.Length = Win32Native.LOAD_STRING_MAX_LENGTH; 

                    int result = UnsafeNativeMethods.LoadString(handle, resource, 
                                     localizedResource, localizedResource.Length); 

                    if (result != 0) { 
                        return localizedResource.ToString();
                    }
                }
            } 
            return String.Empty;
        } 
#endif // FEATURE_WIN32_REGISTRY 

 
#if FEATURE_WIN32_REGISTRY
        //
        // TryGetLocalizedNamesByRegistryKey -
        // 
        // Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry
        // 
        // The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI 
        // resource dll(s).  When the keys do not exist, the function falls back to reading from the standard
        // key-values 
        //
        // This method expects that its caller has already Asserted RegistryPermission.Read
        //
        static private Boolean TryGetLocalizedNamesByRegistryKey(RegistryKey key, out String displayName, out String standardName, out String daylightName) { 
            displayName  = String.Empty;
            standardName = String.Empty; 
            daylightName = String.Empty; 

            // read the MUI_ registry keys 
            String displayNameMuiResource  = key.GetValue(c_muiDisplayValue,  String.Empty, RegistryValueOptions.None) as String;
            String standardNameMuiResource = key.GetValue(c_muiStandardValue, String.Empty, RegistryValueOptions.None) as String;
            String daylightNameMuiResource = key.GetValue(c_muiDaylightValue, String.Empty, RegistryValueOptions.None) as String;
 
            // try to load the strings from the native resource DLL(s)
            if (!String.IsNullOrEmpty(displayNameMuiResource)) { 
                displayName  = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource); 
            }
 
            if (!String.IsNullOrEmpty(standardNameMuiResource)) {
                standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource);
            }
 
            if (!String.IsNullOrEmpty(daylightNameMuiResource)) {
                daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource); 
            } 

            // fallback to using the standard registry keys 
            if (String.IsNullOrEmpty(displayName)) {
                displayName  = key.GetValue(c_displayValue,  String.Empty, RegistryValueOptions.None) as String;
            }
            if (String.IsNullOrEmpty(standardName)) { 
                standardName = key.GetValue(c_standardValue, String.Empty, RegistryValueOptions.None) as String;
            } 
            if (String.IsNullOrEmpty(daylightName)) { 
                daylightName = key.GetValue(c_daylightValue, String.Empty, RegistryValueOptions.None) as String;
            } 

            return true;
        }
#endif // FEATURE_WIN32_REGISTRY 

 
 
#if FEATURE_WIN32_REGISTRY
        // 
        // TryGetTimeZoneByRegistryKey -
        //
        // Helper function that takes a string representing a  registry key name
        // and returns a TimeZoneInfo instance. 
        //
        // returns 
        //     TimeZoneInfoResult.InvalidTimeZoneException, 
        //     TimeZoneInfoResult.TimeZoneNotFoundException,
        //     TimeZoneInfoResult.SecurityException, 
        //     TimeZoneInfoResult.Success
        //
        //
        // Standard Time Zone Registry Data 
        // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        // HKLM 
        //     Software 
        //         Microsoft
        //             Windows NT 
        //                 CurrentVersion
        //                     Time Zones
        //                         
        // * STD,         REG_SZ "Standard Time Name" 
        //                       (For OS installed zones, this will always be English)
        // * MUI_STD,     REG_SZ "@tzres.dll,-1234" 
        //                       Indirect string to localized resource for Standard Time, 
        //                       add "%windir%\system32\" after "@"
        // * DLT,         REG_SZ "Daylight Time Name" 
        //                       (For OS installed zones, this will always be English)
        // * MUI_DLT,     REG_SZ "@tzres.dll,-1234"
        //                       Indirect string to localized resource for Daylight Time,
        //                       add "%windir%\system32\" after "@" 
        // * Display,     REG_SZ "Display Name like (GMT-8:00) Pacific Time..."
        // * MUI_Display, REG_SZ "@tzres.dll,-1234" 
        //                       Indirect string to localized resource for the Display, 
        //                       add "%windir%\system32\" after "@"
        // * TZI,         REG_BINARY REG_TZI_FORMAT 
        //                       See Win32Native.RegistryTimeZoneInformation
        //
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)] 
        // @
        static private TimeZoneInfoResult TryGetTimeZoneByRegistryKey(string id, out TimeZoneInfo value, out Exception e) { 
            e = null; 

            try { 
                PermissionSet permSet = new PermissionSet(PermissionState.None);
                permSet.AddPermission(new RegistryPermission(RegistryPermissionAccess.Read, c_timeZonesRegistryHivePermissionList));
                permSet.Assert();
 
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(
                                  String.Format(CultureInfo.InvariantCulture, "{0}\\{1}", 
                                      c_timeZonesRegistryHive, id), 
#if FEATURE_MACL
                                  RegistryKeyPermissionCheck.Default, 
                                  System.Security.AccessControl.RegistryRights.ReadKey
#else
                                  false
#endif 
                                  )) {
 
                    if (key == null) { 
                        value = null;
                        return TimeZoneInfoResult.TimeZoneNotFoundException; 
                    }

                    Win32Native.RegistryTimeZoneInformation defaultTimeZoneInformation;
                    Byte[] regValue = key.GetValue(c_timeZoneInfoValue, null, RegistryValueOptions.None) as Byte[]; 
                    if (regValue == null || regValue.Length != c_regByteLength) {
                        // the registry value could not be cast to a byte array 
                        value = null; 
                        return TimeZoneInfoResult.InvalidTimeZoneException;
                    } 
                    defaultTimeZoneInformation = new Win32Native.RegistryTimeZoneInformation(regValue);

                    AdjustmentRule[] adjustmentRules;
                    if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e)) { 
                        value = null;
                        return TimeZoneInfoResult.InvalidTimeZoneException; 
                    } 

                    string displayName; 
                    string standardName;
                    string daylightName;

                    if (!TryGetLocalizedNamesByRegistryKey(key, out displayName, out standardName, out daylightName)) { 
                        value = null;
                        return TimeZoneInfoResult.InvalidTimeZoneException; 
                    } 

                    try { 
                        value = new TimeZoneInfo(
                            id,
                            new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0),
                            displayName, 
                            standardName,
                            daylightName, 
                            adjustmentRules, 
                            false);
 
                        return TimeZoneInfoResult.Success;
                    }
                    catch (ArgumentException ex) {
                        // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException 
                        value = null;
                        e = ex; 
                        return TimeZoneInfoResult.InvalidTimeZoneException; 
                    }
                    catch (InvalidTimeZoneException ex) { 
                        // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException
                        value = null;
                        e = ex;
                        return TimeZoneInfoResult.InvalidTimeZoneException; 
                    }
 
                } 
            }
            finally { 
                PermissionSet.RevertAssert();
            }
        }
#endif // FEATURE_WIN32_REGISTRY 

 
#if FEATURE_WIN32_REGISTRY 
        //
        // TryGetTimeZone - 
        //
        // Helper function for retrieving a TimeZoneInfo object by .
        //
        // This function may return null. 
        //
        static private TimeZoneInfoResult TryGetTimeZone(string id, Boolean dstDisabled, out TimeZoneInfo value, out Exception e) { 
            TimeZoneInfoResult result = TimeZoneInfoResult.Success; 
            e = null;
            TimeZoneInfo match = null; 

            // check the cache
            if (s_systemTimeZones.TryGetValue(id, out match)) {
                if (dstDisabled && match.m_supportsDaylightSavingTime) { 
                    // we found a cache hit but we want a time zone without DST and this one has DST data
                    value = CreateCustomTimeZone(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName); 
                } 
                else {
                    value = new TimeZoneInfo(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName, 
                                          match.m_daylightDisplayName, match.m_adjustmentRules, false);
                }
                return result;
            } 

            // fall back to reading from the local machine 
            // when the cache is not fully populated 
            if (!s_allSystemTimeZonesRead) {
                result = TryGetTimeZoneByRegistryKey(id, out match, out e); 
                if (result == TimeZoneInfoResult.Success) {
                    s_systemTimeZones.Add(id, match);

                    if (dstDisabled && match.m_supportsDaylightSavingTime) { 
                        // we found a cache hit but we want a time zone without DST and this one has DST data
                        value = CreateCustomTimeZone(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName); 
                    } 
                    else {
                        value = new TimeZoneInfo(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName, 
                                              match.m_daylightDisplayName, match.m_adjustmentRules, false);
                    }
                }
                else { 
                    value = null;
                } 
            } 
            else {
                result = TimeZoneInfoResult.TimeZoneNotFoundException; 
                value = null;
            }

            return result; 
        }
#endif // FEATURE_WIN32_REGISTRY 
 

#if FEATURE_CORECLR 
        // TZFILE(5)                   BSD File Formats Manual                  TZFILE(5)
        //
        // NAME
        //      tzfile -- timezone information 
        //
        // SYNOPSIS 
        //      #include "/usr/src/lib/libc/stdtime/tzfile.h" 
        //
        // DESCRIPTION 
        //      The time zone information files used by tzset(3) begin with the magic
        //      characters ``TZif'' to identify them as time zone information files, fol-
        //      lowed by sixteen bytes reserved for future use, followed by four four-
        //      byte values written in a ``standard'' byte order (the high-order byte of 
        //      the value is written first).  These values are, in order:
        // 
        //      tzh_ttisgmtcnt  The number of UTC/local indicators stored in the file. 
        //      tzh_ttisstdcnt  The number of standard/wall indicators stored in the
        //                      file. 
        //      tzh_leapcnt     The number of leap seconds for which data is stored in
        //                      the file.
        //      tzh_timecnt     The number of ``transition times'' for which data is
        //                      stored in the file. 
        //      tzh_typecnt     The number of ``local time types'' for which data is
        //                      stored in the file (must not be zero). 
        //      tzh_charcnt     The number of characters of ``time zone abbreviation 
        //                      strings'' stored in the file.
        // 
        //      The above header is followed by tzh_timecnt four-byte values of type
        //      long, sorted in ascending order.  These values are written in ``stan-
        //      dard'' byte order.  Each is used as a transition time (as returned by
        //      time(3)) at which the rules for computing local time change.  Next come 
        //      tzh_timecnt one-byte values of type unsigned char; each one tells which
        //      of the different types of ``local time'' types described in the file is 
        //      associated with the same-indexed transition time.  These values serve as 
        //      indices into an array of ttinfo structures that appears next in the file;
        //      these structures are defined as follows: 
        //
        //            struct ttinfo {
        //                    long    tt_gmtoff;
        //                    int     tt_isdst; 
        //                    unsigned int    tt_abbrind;
        //            }; 
        // 
        //      Each structure is written as a four-byte value for tt_gmtoff of type
        //      long, in a standard byte order, followed by a one-byte value for tt_isdst 
        //      and a one-byte value for tt_abbrind.  In each structure, tt_gmtoff gives
        //      the number of seconds to be added to UTC, tt_isdst tells whether tm_isdst
        //      should be set by localtime(3) and tt_abbrind serves as an index into the
        //      array of time zone abbreviation characters that follow the ttinfo struc- 
        //      ture(s) in the file.
        // 
        //      Then there are tzh_leapcnt pairs of four-byte values, written in standard 
        //      byte order; the first value of each pair gives the time (as returned by
        //      time(3)) at which a leap second occurs; the second gives the total number 
        //      of leap seconds to be applied after the given time.  The pairs of values
        //      are sorted in ascending order by time.b
        //
        //      Then there are tzh_ttisstdcnt standard/wall indicators, each stored as a 
        //      one-byte value; they tell whether the transition times associated with
        //      local time types were specified as standard time or wall clock time, and 
        //      are used when a time zone file is used in handling POSIX-style time zone 
        //      environment variables.
        // 
        //      Finally there are tzh_ttisgmtcnt UTC/local indicators, each stored as a
        //      one-byte value; they tell whether the transition times associated with
        //      local time types were specified as UTC or local time, and are used when a
        //      time zone file is used in handling POSIX-style time zone environment 
        //      variables.
        // 
        //      localtime uses the first standard-time ttinfo structure in the file (or 
        //      simply the first ttinfo structure in the absence of a standard-time
        //      structure) if either tzh_timecnt is zero or the time argument is less 
        //      than the first transition time recorded in the file.
        //
        // SEE ALSO
        //      ctime(3), time2posix(3), zic(8) 
        //
        // BSD                           September 13, 1994                           BSD 
        // 
        //
        // 
        // TIME(3)                  BSD Library Functions Manual                  TIME(3)
        //
        // NAME
        //      time -- get time of day 
        //
        // LIBRARY 
        //      Standard C Library (libc, -lc) 
        //
        // SYNOPSIS 
        //      #include 
        //
        //      time_t
        //      time(time_t *tloc); 
        //
        // DESCRIPTION 
        //      The time() function returns the value of time in seconds since 0 hours, 0 
        //      minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without
        //      including leap seconds.  If an error occurs, time() returns the value 
        //      (time_t)-1.
        //
        //      The return value is also stored in *tloc, provided that tloc is non-null.
        // 
        // ERRORS
        //      The time() function may fail for any of the reasons described in 
        //      gettimeofday(2). 
        //
        // SEE ALSO 
        //      gettimeofday(2), ctime(3)
        //
        // STANDARDS
        //      The time function conforms to IEEE Std 1003.1-2001 (``POSIX.1''). 
        //
        // BUGS 
        //      Neither ISO/IEC 9899:1999 (``ISO C99'') nor IEEE Std 1003.1-2001 
        //      (``POSIX.1'') requires time() to set errno on failure; thus, it is impos-
        //      sible for an application to distinguish the valid time value -1 (repre- 
        //      senting the last UTC second of 1969) from the error return value.
        //
        //      Systems conforming to earlier versions of the C and POSIX standards
        //      (including older versions of FreeBSD) did not set *tloc in the error 
        //      case.
        // 
        // HISTORY 
        //      A time() function appeared in Version 6 AT&T UNIX.
        // 
        // BSD                              July 18, 2003                             BSD
        //
        //
 
        //
        // TZif_CalculateTransitionTime - 
        // 
        // Example inputs:
        // ----------------- 
        // utc               =     1918-03-31T10:00:00.0000000Z
        // transitionType    =     {-08:00:00  DST=False,  Index 4}
        // standardTime      =     False
        // gmtTime           =     False 
        //
        static private TransitionTime TZif_CalculateTransitionTime(DateTime utc, TimeSpan offset, 
                                                                   TZifType transitionType, Boolean standardTime, 
                                                                   Boolean gmtTime, out DateTime ruleDate) {
 
            // convert from UTC to local clock time
            Int64 ticks = utc.Ticks + offset.Ticks;
            if (ticks > DateTime.MaxValue.Ticks) {
                utc = DateTime.MaxValue; 
            }
            else if (ticks < DateTime.MinValue.Ticks) { 
                utc = DateTime.MinValue; 
            }
            else { 
                utc = new DateTime(ticks);
            }

            DateTime timeOfDay = new DateTime(1, 1, 1, utc.Hour, utc.Minute, utc.Second, utc.Millisecond); 
            int month = utc.Month;
            int day = utc.Day; 
 
            ruleDate = new DateTime(utc.Year, utc.Month, utc.Day);
            // 
            return TransitionTime.CreateFixedDateRule(timeOfDay, month, day);
        }

        static private void TZif_GenerateAdjustmentRules(out AdjustmentRule[] rules, DateTime[] dts, Byte[] typeOfLocalTime, 
                                                         TZifType[] transitionType, Boolean[] StandardTime, Boolean[] GmtTime) {
            rules = null; 
 
            int index = 0;
            List rulesList = new List(1); 
            bool succeeded = true;

            while (succeeded && index < dts.Length) {
                succeeded = TZif_GenerateAdjustmentRule(ref index, ref rulesList, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime); 
            }
 
            rules = rulesList.ToArray(); 
            if (rules != null && rules.Length == 0) {
                rules = null; 
            }
        }

 
        static private bool TZif_GenerateAdjustmentRule(ref int startIndex, ref List rulesList, DateTime[] dts, Byte[] typeOfLocalTime,
                                                                  TZifType[] transitionType, Boolean[] StandardTime, Boolean[] GmtTime) { 
 
            int index = startIndex;
            bool Dst = false; 
            int DstStartIndex = -1;
            int DstEndIndex = -1;
            DateTime startDate = DateTime.MinValue.Date;
            DateTime endDate = DateTime.MaxValue.Date; 

 
            // find the next DST transition start time index 
            while (!Dst && index < typeOfLocalTime.Length) {
                int typeIndex = typeOfLocalTime[index]; 
                if (typeIndex < transitionType.Length && transitionType[typeIndex].IsDst) {
                    // found the next DST transition start time
                    Dst = true;
                    DstStartIndex = index; 
                }
                else { 
                    index++; 
                }
            } 

            // find the next DST transition end time index
            while (Dst && index < typeOfLocalTime.Length) {
                int typeIndex = typeOfLocalTime[index]; 
                if (typeIndex < transitionType.Length && !transitionType[typeIndex].IsDst) {
                    // found the next DST transition end time 
                    Dst = false; 
                    DstEndIndex = index;
                } 
                else {
                    index++;
                }
            } 

 
            // 
            // construct the adjustment rule from the two indices
            // 
            if (DstStartIndex >= 0) {
                DateTime startTransitionDate = dts[DstStartIndex];
                DateTime endTransitionDate;
 

                if (DstEndIndex == -1) { 
                    // we found a DST start but no DST end; in this case use the 
                    // prior non-DST entry if it exists, else use the current entry for both start and end (e.g., zero daylightDelta)
                    if (DstStartIndex > 0) { 
                        DstEndIndex = DstStartIndex - 1;
                    }
                    else {
                        DstEndIndex = DstStartIndex; 
                    }
                    endTransitionDate = DateTime.MaxValue; 
                } 
                else {
                    endTransitionDate = dts[DstEndIndex]; 
                }

                int dstStartTypeIndex = typeOfLocalTime[DstStartIndex];
                int dstEndTypeIndex = typeOfLocalTime[DstEndIndex]; 

                TimeSpan daylightBias =  transitionType[dstStartTypeIndex].UtcOffset - transitionType[dstEndTypeIndex].UtcOffset; 
                // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns 
                // with DateTimeOffset, SQL Server, and the W3C XML Specification
                if (daylightBias.Ticks % TimeSpan.TicksPerMinute != 0) { 
                    daylightBias = new TimeSpan(daylightBias.Hours, daylightBias.Minutes, 0);
                }

                // 
                // the normal case is less than 12 months between transition times.  However places like ----/Catamarca
                // have DST from 1946-1963 straight without a gap.  In that case we need to create a series of Adjustment 
                // Rules to fudge the multi-year DST period 
                //
                if ((endTransitionDate - startTransitionDate).Ticks <= TimeSpan.TicksPerDay * 364) { 
                    TransitionTime dstStart;
                    TransitionTime dstEnd;
                    TimeSpan startTransitionOffset = (DstStartIndex > 0 ? transitionType[typeOfLocalTime[DstStartIndex - 1]].UtcOffset : transitionType[dstEndTypeIndex].UtcOffset);
                    TimeSpan endTransitionOffset = (DstEndIndex > 0 ? transitionType[typeOfLocalTime[DstEndIndex - 1]].UtcOffset : transitionType[dstStartTypeIndex].UtcOffset); 

 
                    dstStart = TZif_CalculateTransitionTime(startTransitionDate, 
                                                                           startTransitionOffset,
                                                                           transitionType[dstStartTypeIndex], 
                                                                           StandardTime[dstStartTypeIndex],
                                                                           GmtTime[dstStartTypeIndex],
                                                                           out startDate);
 
                    dstEnd  = TZif_CalculateTransitionTime(endTransitionDate,
                                                                           endTransitionOffset, 
                                                                           transitionType[dstEndTypeIndex], 
                                                                           StandardTime[dstEndTypeIndex],
                                                                           GmtTime[dstEndTypeIndex], 
                                                                           out endDate);


 
                    // calculate the AdjustmentRule end date
                    if (DstStartIndex >= DstEndIndex) { 
                        // we found a DST start but no DST end 
                        endDate = DateTime.MaxValue.Date;
                    } 

                    AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(startDate, endDate, daylightBias, dstStart, dstEnd);
                    rulesList.Add(r);
                } 
                else {
                    // create the multi-year DST rule series: 
                    // 
                    // For example ----/Catamarca:
                    //     1946-10-01T04:00:00.0000000Z {-03:00:00 DST=True} 
                    //     1963-10-01T03:00:00.0000000Z {-04:00:00 DST=False}
                    //
                    // gets converted into a series of overlapping 5/7month adjustment rules:
                    // 
                    // [AdjustmentRule       #0] // start rule
                    // [1946/09/31 - 1947/06/15] // * starts 1 day prior to startTransitionDate 
                    // [start: 10/01 @4:00     ] // * N months long, stopping at month 6 or 11 
                    // [end  : 07/15           ] // notice how the _end_ is outside the range
                    // 
                    // [AdjustmentRule       #1] // middle-year all-DST rule
                    // [1947/06/16 - 1947/11/15] // * starts 1 day after last day in previous rule
                    // [start: 05/15           ] // * 5 months long, stopping at month 6 or 11
                    // [end  : 12/15           ] // notice how the _start and end_ are outside the range 
                    //
                    // [AdjustmentRule       #2] // middle-year all-DST rule 
                    // [1947/11/16 - 1947/06/15] //  * starts 1 day after last day in previous rule 
                    // [start: 10/01           ] //  * 7 months long, stopping at month 6 or 11
                    // [end  : 07/15           ] // notice how the _start and end_ are outside the range 
                    //
                    // .........................
                    //
                    // [AdjustmentRule       #N] // end rule 
                    // [1963/06/16 - 1946/10/02] //   * starts 1 day after last day in previous rule
                    // [start: 05/15           ] //   * N months long, stopping 1 day after endTransitionDate 
                    // [end  : 10/01           ] // notice how the _start_ is outside the range 
                    //
 
                    // create the first rule from N to either 06/15 or 11/15
                    TZif_CreateFirstMultiYearRule(ref rulesList, daylightBias, startTransitionDate, DstStartIndex, dstStartTypeIndex, dstEndTypeIndex,
                                                                                            dts, transitionType, typeOfLocalTime, StandardTime, GmtTime);
 
                    // create the filler rules
                    TZif_CreateMiddleMultiYearRules(ref rulesList, daylightBias, endTransitionDate); 
 
                    // create the last rule
                    TZif_CreateLastMultiYearRule(ref rulesList, daylightBias, endTransitionDate,  DstStartIndex, dstStartTypeIndex, DstEndIndex, dstEndTypeIndex, 
                                                                                            dts, transitionType, typeOfLocalTime, StandardTime, GmtTime);
                }

                startIndex = index + 1; 
                return true;
            } 
 
            // setup the start values for the next call to TZif_GenerateAdjustmentRule(...)
            startIndex = index + 1; 
            return false; // did not create a new AdjustmentRule
        }

        static private void TZif_CreateFirstMultiYearRule(ref List rulesList, TimeSpan daylightBias, DateTime startTransitionDate, 
                                                          int DstStartIndex, int dstStartTypeIndex, int dstEndTypeIndex, DateTime[] dts, TZifType[] transitionType,
                                                          Byte[] typeOfLocalTime, bool[] StandardTime, bool[] GmtTime) { 
 
                    // [AdjustmentRule       #0] // start rule
                    // [1946/09/31 - 1947/06/15] // * starts 1 day prior to startTransitionDate 
                    // [start: 10/01 @4:00     ] // * N months long, stopping at month 6 or 11
                    // [end  : 07/15           ] // notice how the _end_ is outside the range

            DateTime startDate; 
            DateTime endDate;
            TransitionTime dstStart; 
            TransitionTime dstEnd; 

            TimeSpan startTransitionOffset = (DstStartIndex > 0 ? transitionType[typeOfLocalTime[DstStartIndex - 1]].UtcOffset : transitionType[dstEndTypeIndex].UtcOffset); 

            dstStart = TZif_CalculateTransitionTime(startTransitionDate,
                                                    startTransitionOffset,
                                                    transitionType[dstStartTypeIndex], 
                                                    StandardTime[dstStartTypeIndex],
                                                    GmtTime[dstStartTypeIndex], 
                                                    out startDate); 

            // 
            // Choosing the endDate based on the startDate:
            //
            // startTransitionDate.Month -> end
            // 1        4|5        8|9       12 
            // [-> 06/15]|[-> 11/15]|[-> 06/15]
            // 
            if (startDate.Month <= 4) { 
                endDate = new DateTime(startDate.Year,   06, 15);
                dstEnd = c_transition7_15; 
            } else if (startDate.Month <= 8) {
                endDate = new DateTime(startDate.Year,   11, 15);
                dstEnd = c_transition12_15;
            } 
            else if (startDate.Year < 9999) {
                endDate = new DateTime(startDate.Year+1, 06, 15); 
                dstEnd = c_transition7_15; 
            }
            else { 
                endDate = DateTime.MaxValue;
                dstEnd = c_transition7_15;
            }
 
            AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(startDate, endDate, daylightBias, dstStart, dstEnd);
            rulesList.Add(r); 
        } 

 
        static private void TZif_CreateLastMultiYearRule(ref List rulesList, TimeSpan daylightBias, DateTime endTransitionDate,
                                                          int DstStartIndex, int dstStartTypeIndex, int DstEndIndex, int dstEndTypeIndex, DateTime[] dts, TZifType[] transitionType,
                                                          Byte[] typeOfLocalTime, bool[] StandardTime, bool[] GmtTime) {
 
                    // [AdjustmentRule       #N] // end rule
                    // [1963/06/16 - 1946/10/02] //   * starts 1 day after last day in previous rule 
                    // [start: 05/15           ] //   * N months long, stopping 1 day after endTransitionDate 
                    // [end  : 10/01           ] // notice how the _start_ is outside the range
 
            DateTime endDate;
            TransitionTime dstEnd;

            TimeSpan endTransitionOffset = (DstEndIndex > 0 ? transitionType[typeOfLocalTime[DstEndIndex - 1]].UtcOffset : transitionType[dstStartTypeIndex].UtcOffset); 

 
            dstEnd  = TZif_CalculateTransitionTime(endTransitionDate, 
                                                   endTransitionOffset,
                                                   transitionType[dstEndTypeIndex], 
                                                   StandardTime[dstEndTypeIndex],
                                                   GmtTime[dstEndTypeIndex],
                                                   out endDate);
 
            if (DstStartIndex >= DstEndIndex) {
                // we found a DST start but no DST end 
                endDate = DateTime.MaxValue.Date; 
            }
 
            AdjustmentRule prevRule = rulesList[ rulesList.Count - 1]; // grab the last element of the MultiYearRule sequence
            int y = prevRule.DateEnd.Year;
            if (prevRule.DateEnd.Month <= 6) {
                // create a rule from 06/16/YYYY to endDate 
                AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 06, 16), endDate, daylightBias, c_transition5_15, dstEnd);
                rulesList.Add(r); 
            } 
            else {
                // create a rule from 11/16/YYYY to endDate 
                AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 11, 16), endDate, daylightBias, c_transition10_15, dstEnd);
                rulesList.Add(r);
            }
        } 

 
        static private void TZif_CreateMiddleMultiYearRules(ref List rulesList, TimeSpan daylightBias, DateTime endTransitionDate) { 
                    //
                    // [AdjustmentRule       #1] // middle-year all-DST rule 
                    // [1947/06/16 - 1947/11/15] // * starts 1 day after last day in previous rule
                    // [start: 05/15           ] // * 5 months long, stopping at month 6 or 11
                    // [end  : 12/15           ] // notice how the _start and end_ are outside the range
                    // 
                    // [AdjustmentRule       #2] // middle-year all-DST rule
                    // [1947/11/16 - 1947/06/15] //  * starts 1 day after last day in previous rule 
                    // [start: 10/01           ] //  * 7 months long, stopping at month 6 or 11 
                    // [end  : 07/15           ] // notice how the _start and end_ are outside the range
                    // 
                    // .........................

            AdjustmentRule prevRule = rulesList[ rulesList.Count - 1]; // grab the first element of the MultiYearRule sequence
            DateTime endDate; 

            // 
            // Choosing the last endDate based on the endTransitionDate 
            //
            // endTransitionDate.Month -> end 
            // 1        4|5        8|9       12
            // [11/15 <-]|[11/15 <-]|[06/15 <-]
            //
            if (endTransitionDate.Month <= 8) { 
                // set the end date to 11/15/YYYY-1
                endDate = new DateTime(endTransitionDate.Year - 1, 11, 15); 
            } 
            else {
                // set the end date to 06/15/YYYY 
                endDate = new DateTime(endTransitionDate.Year, 06, 15);
            }

            while (prevRule.DateEnd < endDate) { 
                // the last endDate will be on either 06/15 or 11/15
                int y = prevRule.DateEnd.Year; 
                if (prevRule.DateEnd.Month <= 6) { 
                    // create a rule from 06/16/YYYY to 11/15/YYYY
                    AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 06, 16), new DateTime(y, 11, 15), 
                                                                           daylightBias, c_transition5_15, c_transition12_15);
                    prevRule = r;
                    rulesList.Add(r);
                } 
                else {
                    // create a rule from 11/16/YYYY to 06/15/YYYY+1 
                    AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 11, 16), new DateTime(y+1, 06, 15), 
                                                                           daylightBias, c_transition10_15, c_transition7_15);
                    prevRule = r; 
                    rulesList.Add(r);
                }
            }
        } 

 
        // Returns the Substring from zoneAbbreviations starting at index and ending at '\0' 
        // zoneAbbreviations is expected to be in the form: "PST\0PDT\0PWT\0\PPT"
        static private String TZif_GetZoneAbbreviation(String zoneAbbreviations, int index) { 
            int lastIndex = zoneAbbreviations.IndexOf('\0', index);
            if (lastIndex > 0) {
                return zoneAbbreviations.Substring(index, lastIndex - index);
            } 
            else {
                return zoneAbbreviations.Substring(index); 
            } 
        }
 
        // verify the 'index' is referenced from the typeOfLocalTime byte array.
        //
        static private Boolean TZif_ValidTransitionType(int index, Byte[] typeOfLocalTime) {
           Boolean result = false; 

           if (typeOfLocalTime != null) { 
               for (int i = 0; !result && i < typeOfLocalTime.Length; i++) { 
                   if (index == typeOfLocalTime[i]) {
                       result = true; 
                   }
               }
           }
           return result; 
        }
 
        // Converts an array of bytes into an int - always using standard byte order (Big Endian) 
        // per TZif file standard
        [System.Security.SecuritySafeCritical]  // auto-generated 
        static private unsafe int TZif_ToInt32 (byte[]value, int startIndex) {
            fixed( byte * pbyte = &value[startIndex]) {
                return (*pbyte << 24) | (*(pbyte + 1) << 16)  | (*(pbyte + 2) << 8) | (*(pbyte + 3));
            } 
        }
 
        static private void TZif_ParseRaw(Byte[] data, out TZifHead t, out DateTime[] dts, out Byte[] typeOfLocalTime, out TZifType[] transitionType, 
                                          out String zoneAbbreviations, out Boolean[] StandardTime, out Boolean[] GmtTime) {
 
            // initialize the out parameters in case the TZifHead ctor throws
            dts = null;
            typeOfLocalTime = null;
            transitionType = null; 
            zoneAbbreviations = String.Empty;
            StandardTime = null; 
            GmtTime = null; 

            // read in the 44-byte TZ header containing the count/length fields 
            //
            t = new TZifHead(data, 0);
            int index = TZifHead.Length;
 
            // initialize the containers for the rest of the TZ data
            dts = new DateTime[t.TimeCount]; 
            typeOfLocalTime = new Byte[t.TimeCount]; 
            transitionType = new TZifType[t.TypeCount];
            zoneAbbreviations = String.Empty; 
            StandardTime = new Boolean[t.TypeCount];
            GmtTime = new Boolean[t.TypeCount];

 
            // read in the 4-byte UTC transition points and convert them to Windows
            // 
            for (int i = 0; i < t.TimeCount; i++) { 
                int unixTime = TZif_ToInt32(data, index);
                dts[i] = TZif_UnixTimeToWindowsTime(unixTime); 
                index += 4;
            }

            // read in the Type Indices; there is a 1:1 mapping of UTC transition points to Type Indices 
            // these indices directly map to the array index in the transitionType array below
            // 
            for (int i = 0; i < t.TimeCount; i++) { 
                typeOfLocalTime[i] = data[index];
                index += 1; 
            }

            // read in the Type table.  Each 6-byte entry represents
            // {UtcOffset, IsDst, AbbreviationIndex} 
            //
            // each AbbreviationIndex is a character index into the zoneAbbreviations string below 
            // 
            for (int i = 0; i < t.TypeCount; i++) {
                transitionType[i] = new TZifType(data, index); 
                index += 6;
            }

            // read in the Abbreviation ASCII string.  This string will be in the form: 
            // "PST\0PDT\0PWT\0\PPT"
            // 
            System.Text.Encoding enc = new System.Text.UTF8Encoding(); 
            zoneAbbreviations = enc.GetString(data, index, (int)t.CharCount);
            index += (int)t.CharCount; 

            // skip ahead of the Leap-Seconds Adjustment data.  In a future release, consider adding
            // support for Leap-Seconds
            // 
            index += (int)(t.LeapCount * 8); // skip the leap second transition times
 
            // read in the Standard Time table.  There should be a 1:1 mapping between Type-Index and Standard 
            // Time table entries.
            // 
            // TRUE     =     transition time is standard time
            // FALSE    =     transition time is wall clock time
            // ABSENT   =     transition time is wall clock time
            // 
            for (int i = 0; i < t.IsStdCount && i < t.TypeCount && index < data.Length; i++) {
                StandardTime[i] = (data[index++] != 0); 
            } 

            // read in the GMT Time table.  There should be a 1:1 mapping between Type-Index and GMT Time table 
            // entries.
            //
            // TRUE     =     transition time is UTC
            // FALSE    =     transition time is local time 
            // ABSENT   =     transition time is local time
            // 
            for (int i = 0; i < t.IsGmtCount && i < t.TypeCount && index < data.Length; i++) { 
                GmtTime[i] = (data[index++] != 0);
            } 
        }


        // Windows NT time is specified as the number of 100 nanosecond intervals since January 1, 1601. 
        // UNIX time is specified as the number of seconds since January 1, 1970. There are 134,774 days
        // (or 11,644,473,600 seconds) between these dates. 
        // 
        private static DateTime TZif_UnixTimeToWindowsTime(int unixTime) {
            // Add 11,644,473,600 and multiply by 10,000,000. 
            Int64 ntTime = (((Int64)unixTime) + 11644473600) * 10000000;
            return DateTime.FromFileTimeUtc(ntTime);
        }
#endif // FEATURE_CORECLR 

 
        // 
        // UtcOffsetOutOfRange -
        // 
        // Helper function that validates the TimeSpan is within +/- 14.0 hours
        //
        [Pure]
        static internal Boolean UtcOffsetOutOfRange(TimeSpan offset) { 
            return (offset.TotalHours < -14.0 || offset.TotalHours > 14.0);
        } 
 

        // 
        // ValidateTimeZoneInfo -
        //
        // Helper function that performs all of the validation checks for the
        // factory methods and deserialization callback 
        //
        // returns a Boolean indicating whether the AdjustmentRule[] supports DST 
        // 
        static private void ValidateTimeZoneInfo(
                String id, 
                TimeSpan baseUtcOffset,
                AdjustmentRule [] adjustmentRules,
                out Boolean adjustmentRulesSupportDst) {
 
            if (id == null) {
                throw new ArgumentNullException("id"); 
            } 

            if (id.Length == 0) { 
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidId", id), "id");
            }

            if (UtcOffsetOutOfRange(baseUtcOffset)) { 

                throw new ArgumentOutOfRangeException("baseUtcOffset", Environment.GetResourceString("ArgumentOutOfRange_UtcOffset")); 
            } 

            if (baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) { 
                throw new ArgumentException(Environment.GetResourceString("Argument_TimeSpanHasSeconds"), "baseUtcOffset");
            }
            Contract.EndContractBlock();
 
            adjustmentRulesSupportDst = false;
 
            // 
            // "adjustmentRules" can either be null or a valid array of AdjustmentRule objects.
            // A valid array is one that does not contain any null elements and all elements 
            // are sorted in chronological order
            //

            if (adjustmentRules != null && adjustmentRules.Length != 0) { 
                adjustmentRulesSupportDst = true;
                AdjustmentRule prev = null; 
                AdjustmentRule current = null; 
                for (int i = 0; i < adjustmentRules.Length; i++) {
                    prev = current; 
                    current = adjustmentRules[i];

                    if (current == null) {
                        throw new InvalidTimeZoneException(Environment.GetResourceString("Argument_AdjustmentRulesNoNulls")); 
                    }
 
                    // 

 

                    if (UtcOffsetOutOfRange(baseUtcOffset + current.DaylightDelta)) {
                        throw new InvalidTimeZoneException(Environment.GetResourceString("ArgumentOutOfRange_UtcOffsetAndDaylightDelta"));
                    } 

 
                    if (prev != null && current.DateStart <= prev.DateEnd) { 
                        // verify the rules are in chronological order and the DateStart/DateEnd do not overlap
                        throw new InvalidTimeZoneException(Environment.GetResourceString("Argument_AdjustmentRulesOutOfOrder")); 
                    }
                }
            }
        } 

/*=========================================================== 
** 
** Class: TimeZoneInfo.AdjustmentRule
** 
**
** Purpose:
** This class is used to represent a Dynamic TimeZone.  It
** has methods for converting a DateTime to UTC from local time 
** and to local time from UTC and methods for getting the
** standard name and daylight name of the time zone. 
** 
**
============================================================*/ 
        [Serializable]
        [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
        [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
        sealed public class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback { 

            // ---- SECTION:  members supporting exposed properties -------------* 
            private DateTime m_dateStart; 
            private DateTime m_dateEnd;
            private TimeSpan m_daylightDelta; 
            private TransitionTime m_daylightTransitionStart;
            private TransitionTime m_daylightTransitionEnd;

 
            // ---- SECTION: public properties --------------*
            public DateTime  DateStart { 
                get { 
                    return this.m_dateStart;
                } 
            }

            public DateTime  DateEnd {
                get { 
                    return this.m_dateEnd;
                } 
            } 

            public TimeSpan DaylightDelta { 
                get {
                    return this.m_daylightDelta;
                }
            } 

 
            public TransitionTime DaylightTransitionStart { 
                get {
                    return this.m_daylightTransitionStart; 
                }
            }

 
            public TransitionTime DaylightTransitionEnd {
                get { 
                    return this.m_daylightTransitionEnd; 
                }
            } 


            // ---- SECTION: public methods --------------*
 
            //IEquatable
            public bool Equals(AdjustmentRule other) { 
                bool equals = (other != null 
                     && this.m_dateStart == other.m_dateStart
                     && this.m_dateEnd  == other.m_dateEnd 
                     && this.m_daylightDelta == other.m_daylightDelta);

                equals = equals && this.m_daylightTransitionEnd.Equals(other.m_daylightTransitionEnd)
                         && this.m_daylightTransitionStart.Equals(other.m_daylightTransitionStart); 

                return equals; 
            } 

 
            public override int GetHashCode() {
                return m_dateStart.GetHashCode();
            }
 

 
            // -------- SECTION: constructors -----------------* 

            private AdjustmentRule() { } 


            // -------- SECTION: factory methods -----------------*
 
            static public AdjustmentRule CreateAdjustmentRule(
                             DateTime dateStart, 
                             DateTime dateEnd, 
                             TimeSpan daylightDelta,
                             TransitionTime daylightTransitionStart, 
                             TransitionTime daylightTransitionEnd) {

                ValidateAdjustmentRule(dateStart, dateEnd, daylightDelta,
                                       daylightTransitionStart, daylightTransitionEnd); 

                AdjustmentRule rule = new AdjustmentRule(); 
 
                rule.m_dateStart = dateStart;
                rule.m_dateEnd   = dateEnd; 
                rule.m_daylightDelta = daylightDelta;
                rule.m_daylightTransitionStart = daylightTransitionStart;
                rule.m_daylightTransitionEnd = daylightTransitionEnd;
 

 
                return rule; 
            }
 

            // ----- SECTION: internal utility methods ----------------*

 
            //
            // ValidateAdjustmentRule - 
            // 
            // Helper function that performs all of the validation checks for the
            // factory methods and deserialization callback 
            //
            static private void ValidateAdjustmentRule(
                             DateTime dateStart,
                             DateTime dateEnd, 
                             TimeSpan daylightDelta,
                             TransitionTime daylightTransitionStart, 
                             TransitionTime daylightTransitionEnd) { 

 
                if (dateStart.Kind != DateTimeKind.Unspecified) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeKindMustBeUnspecified"), "dateStart");
                }
 
                if (dateEnd.Kind != DateTimeKind.Unspecified) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeKindMustBeUnspecified"), "dateEnd"); 
                } 

                if (daylightTransitionStart.Equals(daylightTransitionEnd)) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_TransitionTimesAreIdentical"),
                                                "daylightTransitionEnd");
                }
 

                if (dateStart > dateEnd) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_OutOfOrderDateTimes"), "dateStart"); 
                }
 
                if (TimeZoneInfo.UtcOffsetOutOfRange(daylightDelta)) {
                    throw new ArgumentOutOfRangeException("daylightDelta", daylightDelta,
                        Environment.GetResourceString("ArgumentOutOfRange_UtcOffset"));
                } 

                if (daylightDelta.Ticks % TimeSpan.TicksPerMinute != 0) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_TimeSpanHasSeconds"), 
                        "daylightDelta");
                } 

                if (dateStart.TimeOfDay != TimeSpan.Zero) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeHasTimeOfDay"),
                        "dateStart"); 
                }
 
                if (dateEnd.TimeOfDay != TimeSpan.Zero) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeHasTimeOfDay"),
                        "dateEnd"); 
                }
                Contract.EndContractBlock();
            }
 

 
            // ----- SECTION: private serialization instance methods  ----------------* 

#if FEATURE_SERIALIZATION 
            void IDeserializationCallback.OnDeserialization(Object sender) {
                // OnDeserialization is called after each instance of this class is deserialized.
                // This callback method performs AdjustmentRule validation after being deserialized.
 
                try {
                    ValidateAdjustmentRule(m_dateStart, m_dateEnd, m_daylightDelta, 
                                           m_daylightTransitionStart, m_daylightTransitionEnd); 
                }
                catch (ArgumentException e) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
                }
            }
 
            [System.Security.SecurityCritical]  // auto-generated_required
            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { 
                if (info == null) { 
                    throw new ArgumentNullException("info");
                } 
                Contract.EndContractBlock();

                info.AddValue("DateStart",                  m_dateStart);
                info.AddValue("DateEnd",                    m_dateEnd); 
                info.AddValue("DaylightDelta",              m_daylightDelta);
                info.AddValue("DaylightTransitionStart",    m_daylightTransitionStart); 
                info.AddValue("DaylightTransitionEnd",      m_daylightTransitionEnd); 
            }
 
            AdjustmentRule(SerializationInfo info, StreamingContext context) {
                if (info == null) {
                    throw new ArgumentNullException("info");
                } 

                m_dateStart           = (DateTime)info.GetValue("DateStart", typeof(DateTime)); 
                m_dateEnd             = (DateTime)info.GetValue("DateEnd", typeof(DateTime)); 
                m_daylightDelta       = (TimeSpan)info.GetValue("DaylightDelta", typeof(TimeSpan));
                m_daylightTransitionStart = (TransitionTime)info.GetValue("DaylightTransitionStart", typeof(TransitionTime)); 
                m_daylightTransitionEnd   = (TransitionTime)info.GetValue("DaylightTransitionEnd", typeof(TransitionTime));
            }
#endif
        } 

 
/*=========================================================== 
**
** Class: TimeZoneInfo.TransitionTime 
**
**
** Purpose:
** This class is used to represent a Dynamic TimeZone.  It 
** has methods for converting a DateTime to UTC from local time
** and to local time from UTC and methods for getting the 
** standard name and daylight name of the time zone. 
**
** 
============================================================*/
        [Serializable]
        [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
        [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] 
        public struct TransitionTime : IEquatable, ISerializable, IDeserializationCallback {
 
            // ---- SECTION:  members supporting exposed properties -------------* 
            private DateTime m_timeOfDay;
            private byte m_month; 
            private byte m_week;
            private byte m_day;
            private DayOfWeek m_dayOfWeek;
            private Boolean m_isFixedDateRule; 

 
            // ---- SECTION: public properties --------------* 
            public DateTime TimeOfDay {
                get { 
                    return m_timeOfDay;
                }
            }
 
            public Int32 Month {
                get { 
                    return (int)m_month; 
                }
            } 


            public Int32 Week {
                get { 
                    return (int)m_week;
                } 
            } 

            public Int32 Day { 
                get {
                    return (int)m_day;
                }
            } 

            public DayOfWeek DayOfWeek { 
                get { 
                    return m_dayOfWeek;
                } 
            }

            public Boolean IsFixedDateRule {
                get { 
                    return m_isFixedDateRule;
                } 
            } 

            // ---- SECTION: public methods --------------* 
            [Pure]
            public override bool Equals(Object obj) {
                if (obj is TransitionTime) {
                    return Equals((TransitionTime)obj); 
                }
                return false; 
            } 

            public static bool operator ==(TransitionTime t1, TransitionTime t2) { 
                return t1.Equals(t2);
            }

            public static bool operator !=(TransitionTime t1, TransitionTime t2) { 
                return (!t1.Equals(t2));
            } 
 
            [Pure]
            public bool Equals(TransitionTime other) { 

                bool equal = (this.m_isFixedDateRule == other.m_isFixedDateRule
                             && this.m_timeOfDay == other.m_timeOfDay
                             && this.m_month == other.m_month); 

                if (equal) { 
                    if (other.m_isFixedDateRule) { 
                        equal = (this.m_day == other.m_day);
                    } 
                    else {
                        equal = (this.m_week == other.m_week
                            && this.m_dayOfWeek == other.m_dayOfWeek);
                    } 
                }
                return equal; 
            } 

 
            public override int GetHashCode() {
                return ((int)m_month ^ (int)m_week << 8);
            }
 

            // -------- SECTION: constructors -----------------* 
/* 
            private TransitionTime() {
                m_timeOfDay = new DateTime(); 
                m_month = 0;
                m_week  = 0;
                m_day   = 0;
                m_dayOfWeek = DayOfWeek.Sunday; 
                m_isFixedDateRule = false;
            } 
*/ 

 
            // -------- SECTION: factory methods -----------------*


            static public TransitionTime CreateFixedDateRule( 
                    DateTime timeOfDay,
                    Int32 month, 
                    Int32 day) { 

                return CreateTransitionTime(timeOfDay, month, 1, day, DayOfWeek.Sunday, true); 
            }


            static public TransitionTime CreateFloatingDateRule( 
                    DateTime timeOfDay,
                    Int32 month, 
                    Int32 week, 
                    DayOfWeek dayOfWeek) {
 
                return CreateTransitionTime(timeOfDay, month, week, 1, dayOfWeek, false);
            }

 
            static private TransitionTime CreateTransitionTime(
                    DateTime timeOfDay, 
                    Int32 month, 
                    Int32 week,
                    Int32 day, 
                    DayOfWeek dayOfWeek,
                    Boolean isFixedDateRule) {

                ValidateTransitionTime(timeOfDay, month, week, day, dayOfWeek); 

                TransitionTime t = new TransitionTime(); 
                t.m_isFixedDateRule = isFixedDateRule; 
                t.m_timeOfDay = timeOfDay;
                t.m_dayOfWeek = dayOfWeek; 
                t.m_day = (byte)day;
                t.m_week = (byte)week;
                t.m_month = (byte)month;
 
                return t;
            } 
 

            // ----- SECTION: internal utility methods ----------------* 

            //
            // ValidateTransitionTime -
            // 
            // Helper function that validates a TransitionTime instance
            // 
            static private void ValidateTransitionTime( 
                    DateTime timeOfDay,
                    Int32 month, 
                    Int32 week,
                    Int32 day,
                    DayOfWeek dayOfWeek) {
 
                if (timeOfDay.Kind != DateTimeKind.Unspecified) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeKindMustBeUnspecified"), "timeOfDay"); 
                } 

                // Month range 1-12 
                if (month < 1 || month > 12) {
                    throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_MonthParam"));
                }
 
                // Day range 1-31
                if (day < 1 || day > 31) { 
                    throw new ArgumentOutOfRangeException("day", Environment.GetResourceString("ArgumentOutOfRange_DayParam")); 
                }
 
                // Week range 1-5
                if (week < 1 || week > 5) {
                    throw new ArgumentOutOfRangeException("week", Environment.GetResourceString("ArgumentOutOfRange_Week"));
                } 

                // DayOfWeek range 0-6 
                if ((int)dayOfWeek < 0 || (int)dayOfWeek > 6) { 
                    throw new ArgumentOutOfRangeException("dayOfWeek", Environment.GetResourceString("ArgumentOutOfRange_DayOfWeek"));
                } 
                Contract.EndContractBlock();

                if (timeOfDay.Year != 1 || timeOfDay.Month != 1
                || timeOfDay.Day != 1 || (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0)) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_DateTimeHasTicks"), "timeOfDay");
                } 
            } 

#if FEATURE_SERIALIZATION 
            void IDeserializationCallback.OnDeserialization(Object sender) {
                // OnDeserialization is called after each instance of this class is deserialized.
                // This callback method performs TransitionTime validation after being deserialized.
 
                try {
                    ValidateTransitionTime(m_timeOfDay, (Int32)m_month, (Int32)m_week, (Int32)m_day, m_dayOfWeek); 
                } 
                catch (ArgumentException e) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e); 
                }
            }

 
            [System.Security.SecurityCritical]  // auto-generated_required
            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { 
                if (info == null) { 
                    throw new ArgumentNullException("info");
                } 
                Contract.EndContractBlock();

                info.AddValue("TimeOfDay",       m_timeOfDay);
                info.AddValue("Month",           m_month); 
                info.AddValue("Week",            m_week);
                info.AddValue("Day",             m_day); 
                info.AddValue("DayOfWeek",       m_dayOfWeek); 
                info.AddValue("IsFixedDateRule", m_isFixedDateRule);
            } 

            TransitionTime(SerializationInfo info, StreamingContext context) {
                if (info == null) {
                    throw new ArgumentNullException("info"); 
                }
 
                m_timeOfDay       = (DateTime)info.GetValue("TimeOfDay", typeof(DateTime)); 
                m_month           = (byte)info.GetValue("Month", typeof(byte));
                m_week            = (byte)info.GetValue("Week", typeof(byte)); 
                m_day             = (byte)info.GetValue("Day", typeof(byte));
                m_dayOfWeek       = (DayOfWeek)info.GetValue("DayOfWeek", typeof(DayOfWeek));
                m_isFixedDateRule = (Boolean)info.GetValue("IsFixedDateRule", typeof(Boolean));
            } 
#endif
        } 
 

/*============================================================ 
**
** Class: TimeZoneInfo.StringSerializer
**
** 
** Purpose:
** This class is used to serialize and deserialize TimeZoneInfo 
** objects based on the custom string serialization format 
**
** 
============================================================*/
        sealed private class StringSerializer {

            // ---- SECTION: private members  -------------* 
            private enum State {
                Escaped      = 0, 
                NotEscaped   = 1, 
                StartOfToken = 2,
                EndOfLine    = 3 
            }

            private String m_serializedText;
            private int m_currentTokenStartIndex; 
            private State m_state;
 
            // the majority of the strings contained in the OS time zones fit in 64 chars 
            private const int initialCapacityForString = 64;
            private const char esc = '\\'; 
            private const char sep = ';';
            private const char lhs = '[';
            private const char rhs = ']';
            private const string escString = "\\"; 
            private const string sepString = ";";
            private const string lhsString = "["; 
            private const string rhsString = "]"; 
            private const string escapedEsc = "\\\\";
            private const string escapedSep = "\\;"; 
            private const string escapedLhs = "\\[";
            private const string escapedRhs = "\\]";
            private const string dateTimeFormat  = "MM:dd:yyyy";
            private const string timeOfDayFormat = "HH:mm:ss.FFF"; 

 
            // ---- SECTION: public static methods --------------* 

            // 
            // GetSerializedString -
            //
            // static method that creates the custom serialized string
            // representation of a TimeZoneInfo instance 
            //
            static public String GetSerializedString(TimeZoneInfo zone) { 
                StringBuilder serializedText = new StringBuilder(); 

                // 
                // ;;;;
                //
                serializedText.Append(SerializeSubstitute(zone.Id));
                serializedText.Append(sep); 
                serializedText.Append(SerializeSubstitute(
                           zone.BaseUtcOffset.TotalMinutes.ToString(CultureInfo.InvariantCulture))); 
                serializedText.Append(sep); 
                serializedText.Append(SerializeSubstitute(zone.DisplayName));
                serializedText.Append(sep); 
                serializedText.Append(SerializeSubstitute(zone.StandardName));
                serializedText.Append(sep);
                serializedText.Append(SerializeSubstitute(zone.DaylightName));
                serializedText.Append(sep); 

                AdjustmentRule[] rules = zone.GetAdjustmentRules(); 
 
                if (rules != null && rules.Length > 0) {
                    for (int i = 0; i < rules.Length; i++) { 
                        AdjustmentRule rule = rules[i];

                        serializedText.Append(lhs);
                        serializedText.Append(SerializeSubstitute(rule.DateStart.ToString( 
                                                dateTimeFormat, DateTimeFormatInfo.InvariantInfo)));
                        serializedText.Append(sep); 
                        serializedText.Append(SerializeSubstitute(rule.DateEnd.ToString( 
                                                dateTimeFormat, DateTimeFormatInfo.InvariantInfo)));
                        serializedText.Append(sep); 
                        serializedText.Append(SerializeSubstitute(rule.DaylightDelta.TotalMinutes.ToString(CultureInfo.InvariantCulture)));
                        serializedText.Append(sep);
                        // serialize the TransitionTime's
                        SerializeTransitionTime(rule.DaylightTransitionStart, serializedText); 
                        serializedText.Append(sep);
                        SerializeTransitionTime(rule.DaylightTransitionEnd, serializedText); 
                        serializedText.Append(sep); 
                        serializedText.Append(rhs);
                    } 
                }
                serializedText.Append(sep);
                return serializedText.ToString();
            } 

 
            // 
            // GetDeserializedTimeZoneInfo -
            // 
            // static method that instantiates a TimeZoneInfo from a custom serialized
            // string
            //
            static public TimeZoneInfo GetDeserializedTimeZoneInfo(String source) { 
                StringSerializer s = new StringSerializer(source);
 
                String id              = s.GetNextStringValue(false); 
                TimeSpan baseUtcOffset = s.GetNextTimeSpanValue(false);
                String displayName     = s.GetNextStringValue(false); 
                String standardName    = s.GetNextStringValue(false);
                String daylightName    = s.GetNextStringValue(false);
                AdjustmentRule[] rules = s.GetNextAdjustmentRuleArrayValue(false);
 
                try {
                    return TimeZoneInfo.CreateCustomTimeZone(id, baseUtcOffset, displayName, standardName, daylightName, rules); 
                } 
                catch (ArgumentException ex) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), ex); 
                }
                catch (InvalidTimeZoneException ex) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), ex);
                } 
            }
 
            // ---- SECTION: public instance methods --------------* 

 
            // -------- SECTION: constructors -----------------*

            //
            // StringSerializer - 
            //
            // private constructor - used by GetDeserializedTimeZoneInfo() 
            // 
            private StringSerializer(String str) {
                m_serializedText = str; 
                m_state          = State.StartOfToken;
            }

 

            // ----- SECTION: internal static utility methods ----------------* 
 
            //
            // SerializeSubstitute - 
            //
            // returns a new string with all of the reserved sub-strings escaped
            //
            // ";" -> "\;" 
            // "[" -> "\["
            // "]" -> "\]" 
            // "\" -> "\\" 
            //
            static private String SerializeSubstitute(String text) { 
                text = text.Replace(escString, escapedEsc);
                text = text.Replace(lhsString, escapedLhs);
                text = text.Replace(rhsString, escapedRhs);
                return text.Replace(sepString, escapedSep); 
            }
 
 
            //
            // SerializeTransitionTime - 
            //
            // Helper method to serialize a TimeZoneInfo.TransitionTime object
            //
            static private void SerializeTransitionTime(TransitionTime time, StringBuilder serializedText) { 
                serializedText.Append(lhs);
                Int32 fixedDate = (time.IsFixedDateRule ? 1 : 0); 
                serializedText.Append(fixedDate.ToString(CultureInfo.InvariantCulture)); 
                serializedText.Append(sep);
 
                if (time.IsFixedDateRule) {
                    serializedText.Append(SerializeSubstitute(time.TimeOfDay.ToString(timeOfDayFormat, DateTimeFormatInfo.InvariantInfo)));
                    serializedText.Append(sep);
                    serializedText.Append(SerializeSubstitute(time.Month.ToString(CultureInfo.InvariantCulture))); 
                    serializedText.Append(sep);
                    serializedText.Append(SerializeSubstitute(time.Day.ToString(CultureInfo.InvariantCulture))); 
                    serializedText.Append(sep); 
                }
                else { 
                    serializedText.Append(SerializeSubstitute(time.TimeOfDay.ToString(timeOfDayFormat, DateTimeFormatInfo.InvariantInfo)));
                    serializedText.Append(sep);
                    serializedText.Append(SerializeSubstitute(time.Month.ToString(CultureInfo.InvariantCulture)));
                    serializedText.Append(sep); 
                    serializedText.Append(SerializeSubstitute(time.Week.ToString(CultureInfo.InvariantCulture)));
                    serializedText.Append(sep); 
                    serializedText.Append(SerializeSubstitute(((int)time.DayOfWeek).ToString(CultureInfo.InvariantCulture))); 
                    serializedText.Append(sep);
                } 
                serializedText.Append(rhs);
            }

            // 
            // VerifyIsEscapableCharacter -
            // 
            // Helper function to determine if the passed in string token is allowed to be preceeded by an escape sequence token 
            //
            static private void VerifyIsEscapableCharacter(char c) { 
               if (c != esc && c != sep && c != lhs && c != rhs) {
                   throw new SerializationException(Environment.GetResourceString("Serialization_InvalidEscapeSequence", c));
               }
            } 

            // ----- SECTION: internal instance utility methods ----------------* 
 
            //
            // SkipVersionNextDataFields - 
            //
            // Helper function that reads past "v.Next" data fields.  Receives a "depth" parameter indicating the
            // current relative nested bracket depth that m_currentTokenStartIndex is at.  The function ends
            // successfully when "depth" returns to zero (0). 
            //
            // 
            private void SkipVersionNextDataFields(Int32 depth /* starting depth in the nested brackets ('[', ']')*/) { 
                if (m_currentTokenStartIndex < 0 || m_currentTokenStartIndex >= m_serializedText.Length) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }
                State tokenState = State.NotEscaped;

                // walk the serialized text, building up the token as we go... 
                for (int i = m_currentTokenStartIndex; i < m_serializedText.Length; i++) {
                    if (tokenState == State.Escaped) { 
                        VerifyIsEscapableCharacter(m_serializedText[i]); 
                        tokenState = State.NotEscaped;
                    } 
                    else if (tokenState == State.NotEscaped) {
                        switch (m_serializedText[i]) {
                            case esc:
                                tokenState = State.Escaped; 
                                break;
 
                            case lhs: 
                                depth++;
                                break; 
                            case rhs:
                                depth--;
                                if (depth == 0) {
                                    m_currentTokenStartIndex = i + 1; 
                                    if (m_currentTokenStartIndex >= m_serializedText.Length) {
                                        m_state = State.EndOfLine; 
                                    } 
                                    else {
                                        m_state = State.StartOfToken; 
                                    }
                                    return;
                                }
                                break; 

                            case '\0': 
                                // invalid character 
                                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
 
                            default:
                                break;
                        }
                    } 
                }
 
                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
            }
 

            //
            // GetNextStringValue -
            // 
            // Helper function that reads a string token from the serialized text.  The function
            // updates the m_currentTokenStartIndex to point to the next token on exit.  Also m_state 
            // is set to either State.StartOfToken or State.EndOfLine on exit. 
            //
            // The function takes a parameter "canEndWithoutSeparator". 
            //
            // * When set to 'false' the function requires the string token end with a ";".
            // * When set to 'true' the function requires that the string token end with either
            //   ";", State.EndOfLine, or "]".  In the case that "]" is the terminal case the 
            //   m_currentTokenStartIndex is left pointing at index "]" to allow the caller to update
            //   its depth logic. 
            // 
            private String GetNextStringValue(Boolean canEndWithoutSeparator) {
 
                // first verify the internal state of the object
                if (m_state == State.EndOfLine) {
                    if (canEndWithoutSeparator) {
                        return null; 
                    }
                    else { 
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                    }
                } 
                if (m_currentTokenStartIndex < 0 || m_currentTokenStartIndex >= m_serializedText.Length) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                }
                State tokenState = State.NotEscaped; 
                StringBuilder token = new StringBuilder(initialCapacityForString);
 
                // walk the serialized text, building up the token as we go... 
                for (int i = m_currentTokenStartIndex; i < m_serializedText.Length; i++) {
                    if (tokenState == State.Escaped) { 
                        VerifyIsEscapableCharacter(m_serializedText[i]);
                        token.Append(m_serializedText[i]);
                        tokenState = State.NotEscaped;
                    } 
                    else if (tokenState == State.NotEscaped) {
                        switch (m_serializedText[i]) { 
                            case esc: 
                                tokenState = State.Escaped;
                                break; 

                            case lhs:
                                // '[' is an unexpected character
                                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 

                            case rhs: 
                                if (canEndWithoutSeparator) { 
                                    // if ';' is not a required terminal then treat ']' as a terminal
                                    // leave m_currentTokenStartIndex pointing to ']' so our callers can handle 
                                    // this special case
                                    m_currentTokenStartIndex = i;
                                    m_state = State.StartOfToken;
                                    return token.ToString(); 
                                }
                                else { 
                                    // ']' is an unexpected character 
                                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                                } 

                            case sep:
                                m_currentTokenStartIndex = i + 1;
                                if (m_currentTokenStartIndex >= m_serializedText.Length) { 
                                    m_state = State.EndOfLine;
                                } 
                                else { 
                                    m_state = State.StartOfToken;
                                } 
                                return token.ToString();


                            case '\0': 
                                // invalid character
                                throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
 
                            default:
                                token.Append(m_serializedText[i]); 
                                break;
                        }
                    }
                } 
                //
                // we are at the end of the line 
                // 
                if (tokenState == State.Escaped) {
                   // we are at the end of the serialized text but we are in an escaped state 
                   throw new SerializationException(Environment.GetResourceString("Serialization_InvalidEscapeSequence", String.Empty));
                }

                if (!canEndWithoutSeparator) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                } 
                m_currentTokenStartIndex = m_serializedText.Length; 
                m_state = State.EndOfLine;
                return token.ToString(); 
            }

            //
            // GetNextDateTimeValue - 
            //
            // Helper function to read a DateTime token.  Takes a boolean "canEndWithoutSeparator" 
            // and a "format" string. 
            //
            private DateTime GetNextDateTimeValue(Boolean canEndWithoutSeparator, string format) { 
                String token = GetNextStringValue(canEndWithoutSeparator);
                DateTime time;
                if (!DateTime.TryParseExact(token, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out time)) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }
                return time; 
            } 

            // 
            // GetNextTimeSpanValue -
            //
            // Helper function to read a DateTime token.  Takes a boolean "canEndWithoutSeparator".
            // 
            private TimeSpan GetNextTimeSpanValue(Boolean canEndWithoutSeparator) {
                Int32 token = GetNextInt32Value(canEndWithoutSeparator); 
 
                try {
                    return new TimeSpan(0 /* hours */, token /* minutes */, 0 /* seconds */); 
                }
                catch (ArgumentOutOfRangeException e) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
                } 
            }
 
 
            //
            // GetNextInt32Value - 
            //
            // Helper function to read an Int32 token.  Takes a boolean "canEndWithoutSeparator".
            //
            private Int32 GetNextInt32Value(Boolean canEndWithoutSeparator) { 
                String token = GetNextStringValue(canEndWithoutSeparator);
                Int32 value; 
                if (!Int32.TryParse(token, NumberStyles.AllowLeadingSign /* "[sign]digits" */, CultureInfo.InvariantCulture, out value)) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                } 
                return value;
            }

 
            //
            // GetNextAdjustmentRuleArrayValue - 
            // 
            // Helper function to read an AdjustmentRule[] token.  Takes a boolean "canEndWithoutSeparator".
            // 
            private AdjustmentRule[] GetNextAdjustmentRuleArrayValue(Boolean canEndWithoutSeparator) {
                List rules = new List(1);
                int count = 0;
 
                // individual AdjustmentRule array elements do not require semicolons
                AdjustmentRule rule = GetNextAdjustmentRuleValue(true); 
                while (rule != null) { 
                    rules.Add(rule);
                    count++; 

                    rule = GetNextAdjustmentRuleValue(true);
                }
 
                if (!canEndWithoutSeparator) {
                    // the AdjustmentRule array must end with a separator 
                    if (m_state == State.EndOfLine) { 
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                    } 
                    if (m_currentTokenStartIndex < 0 || m_currentTokenStartIndex >= m_serializedText.Length) {
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                    }
                } 

                return (count != 0 ? rules.ToArray() : null); 
            } 

            // 
            // GetNextAdjustmentRuleValue -
            //
            // Helper function to read an AdjustmentRule token.  Takes a boolean "canEndWithoutSeparator".
            // 
            private AdjustmentRule GetNextAdjustmentRuleValue(Boolean canEndWithoutSeparator) {
                // first verify the internal state of the object 
                if (m_state == State.EndOfLine) { 
                    if (canEndWithoutSeparator) {
                        return null; 
                    }
                    else {
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                    } 
                }
 
                if (m_currentTokenStartIndex < 0 || m_currentTokenStartIndex >= m_serializedText.Length) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                } 

                // check to see if the very first token we see is the separator
                if (m_serializedText[m_currentTokenStartIndex] == sep) {
                    return null; 
                }
 
                // verify the current token is a left-hand-side marker ("[") 
                if (m_serializedText[m_currentTokenStartIndex] != lhs) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }
                m_currentTokenStartIndex++;

                DateTime dateStart           = GetNextDateTimeValue(false, dateTimeFormat); 
                DateTime dateEnd             = GetNextDateTimeValue(false, dateTimeFormat);
                TimeSpan daylightDelta       = GetNextTimeSpanValue(false); 
                TransitionTime daylightStart = GetNextTransitionTimeValue(false); 
                TransitionTime daylightEnd   = GetNextTransitionTimeValue(false);
 
                // verify that the string is now at the right-hand-side marker ("]") ...

                if (m_state == State.EndOfLine || m_currentTokenStartIndex >= m_serializedText.Length) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }
 
                if (m_serializedText[m_currentTokenStartIndex] != rhs) { 
                    // skip ahead of any "v.Next" data at the end of the AdjustmentRule
                    // 
                    //


                    SkipVersionNextDataFields(1); 
                }
                else { 
                    m_currentTokenStartIndex++; 
                }
 
                // create the AdjustmentRule from the deserialized fields ...

                AdjustmentRule rule;
                try { 
                    rule = AdjustmentRule.CreateAdjustmentRule(dateStart, dateEnd, daylightDelta, daylightStart, daylightEnd);
                } 
                catch (ArgumentException e) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
                } 

                // finally set the state to either EndOfLine or StartOfToken for the next caller
                if (m_currentTokenStartIndex >= m_serializedText.Length) {
                    m_state = State.EndOfLine; 
                }
                else { 
                    m_state = State.StartOfToken; 
                }
                return rule; 
            }


            // 
            // GetNextTransitionTimeValue -
            // 
            // Helper function to read a TransitionTime token.  Takes a boolean "canEndWithoutSeparator". 
            //
            private TransitionTime GetNextTransitionTimeValue(Boolean canEndWithoutSeparator) { 

                // first verify the internal state of the object

                if (m_state == State.EndOfLine 
                    || (m_currentTokenStartIndex < m_serializedText.Length
                        && m_serializedText[m_currentTokenStartIndex] == rhs)) { 
                    // 
                    // we are at the end of the line or we are starting at a "]" character
                    // 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                }

                if (m_currentTokenStartIndex < 0 || m_currentTokenStartIndex >= m_serializedText.Length) { 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                } 
 
                // verify the current token is a left-hand-side marker ("[")
 
                if (m_serializedText[m_currentTokenStartIndex] != lhs) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                }
                m_currentTokenStartIndex++; 

                Int32 isFixedDate   = GetNextInt32Value(false); 
 
                if (isFixedDate != 0 && isFixedDate != 1) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }

                TransitionTime transition;
 
                DateTime timeOfDay  = GetNextDateTimeValue(false, timeOfDayFormat);
                timeOfDay = new DateTime(1, 1, 1, timeOfDay.Hour,timeOfDay.Minute,timeOfDay.Second, timeOfDay.Millisecond); 
 
                Int32 month         = GetNextInt32Value(false);
 
                if (isFixedDate == 1) {
                    Int32 day       = GetNextInt32Value(false);

                    try { 
                        transition = TransitionTime.CreateFixedDateRule(timeOfDay, month, day);
                    } 
                    catch (ArgumentException e) { 
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
                    } 
                }
                else {
                    Int32 week      = GetNextInt32Value(false);
                    Int32 dayOfWeek = GetNextInt32Value(false); 

                    try { 
                        transition = TransitionTime.CreateFloatingDateRule(timeOfDay, month, week, (DayOfWeek)dayOfWeek); 
                    }
                    catch (ArgumentException e) { 
                        throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"), e);
                    }

                } 

                // verify that the string is now at the right-hand-side marker ("]") ... 
 
                if (m_state == State.EndOfLine || m_currentTokenStartIndex >= m_serializedText.Length) {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData")); 
                }

                if (m_serializedText[m_currentTokenStartIndex] != rhs) {
                    // skip ahead of any "v.Next" data at the end of the AdjustmentRule 
                    //
                    // 
 

                    SkipVersionNextDataFields(1); 
                }
                else {
                    m_currentTokenStartIndex++;
                } 

                // check to see if the string is now at the separator (";") ... 
                Boolean sepFound = false; 
                if (m_currentTokenStartIndex < m_serializedText.Length
                    && m_serializedText[m_currentTokenStartIndex] == sep) { 
                    // handle the case where we ended on a ";"
                    m_currentTokenStartIndex++;
                    sepFound = true;
                } 

                if (!sepFound && !canEndWithoutSeparator) { 
                    // we MUST end on a separator 
                    throw new SerializationException(Environment.GetResourceString("Serialization_InvalidData"));
                } 


                // finally set the state to either EndOfLine or StartOfToken for the next caller
                if (m_currentTokenStartIndex >= m_serializedText.Length) { 
                    m_state = State.EndOfLine;
                } 
                else { 
                    m_state = State.StartOfToken;
                } 
                return transition;
            }
        }
 
        private class TimeZoneInfoComparer : System.Collections.Generic.IComparer {
            int System.Collections.Generic.IComparer.Compare(TimeZoneInfo x, TimeZoneInfo y)  { 
                // sort by BaseUtcOffset first and by DisplayName second - this is similar to the Windows Date/Time control panel 
                int comparison = x.BaseUtcOffset.CompareTo(y.BaseUtcOffset);
                return comparison == 0 ? String.Compare(x.DisplayName, y.DisplayName, StringComparison.Ordinal) : comparison; 
            }
        }

#if FEATURE_CORECLR 
        private struct TZifType {
            private const int c_len = 6; 
            public static int Length { 
                get {
                    return c_len; 
                }
            }

            public TimeSpan UtcOffset; 
            public Boolean IsDst;
            public Byte AbbreviationIndex; 
 
            public TZifType(Byte[] data, Int32 index) {
                if (data == null || data.Length < index + c_len) { 
                    throw new ArgumentException(Environment.GetResourceString("Argument_TimeZoneInfoInvalidTZif"), "data");
                }
                Contract.EndContractBlock();
                UtcOffset = new TimeSpan(0, 0, TZif_ToInt32(data, index + 00)); 
                IsDst = (data[index + 4] != 0);
                AbbreviationIndex = data[index + 5]; 
            } 
        }
 
        private struct TZifHead {
            private const int c_len = 44;
            public static int Length {
                get { 
                    return c_len;
                } 
            } 

            public TZifHead(Byte[] data, Int32 index) { 
                if (data == null || data.Length < c_len) {
                    throw new ArgumentException("bad data", "data");
                }
                Contract.EndContractBlock(); 

                Magic      = (uint)TZif_ToInt32(data, index + 00); 
 
                if (Magic != 0x545A6966) {
                    // 0x545A6966 = {0x54, 0x5A, 0x69, 0x66} = "TZif" 
                    throw new ArgumentException(Environment.GetResourceString("Argument_TimeZoneInfoBadTZif"), "data");
                }

                // don't use the BitConverter class which parses data 
                // based on the Endianess of the machine architecture.
                // this data is expected to always be in "standard byte order", 
                // regardless of the machine it is being processed on. 

                IsGmtCount = (uint)TZif_ToInt32(data, index + 20); 
                // skip the 16 byte reserved field
                IsStdCount = (uint)TZif_ToInt32(data, index + 24);
                LeapCount  = (uint)TZif_ToInt32(data, index + 28);
                TimeCount  = (uint)TZif_ToInt32(data, index + 32); 
                TypeCount  = (uint)TZif_ToInt32(data, index + 36);
                CharCount  = (uint)TZif_ToInt32(data, index + 40); 
            } 

            public  UInt32    Magic;       // TZ_MAGIC "TZif" 
            // public  Byte[16] Reserved;    // reserved for future use
            public  UInt32    IsGmtCount;  // number of transition time flags
            public  UInt32    IsStdCount;  // number of transition time flags
            public  UInt32    LeapCount;   // number of leap seconds 
            public  UInt32    TimeCount;   // number of transition times
            public  UInt32    TypeCount;   // number of local time types 
            public  UInt32    CharCount;   // number of abbreviated characters 
        }
 
        [SecurityCritical]
        internal static Byte[] GetLocalTzFile() {
            if (Environment.OSVersion.Platform != PlatformID.MacOSX)
                throw new NotImplementedException(); 

            byte[] toReturn = null; 
            SafeCFCreateRuleHandle tz; 
            SafeCFGetRuleHandle data;
 
            tz = CFTimeZoneCopyDefault();
            if (tz.IsInvalid)
                return null;
 
            data = CFTimeZoneGetData(tz);
            if (data.IsInvalid) 
                return null; 

            toReturn = new byte[CFDataGetLength(data)]; 
            CFRange range = new CFRange(0, toReturn.Length);
            CFDataGetBytes(data, range, toReturn);

            return toReturn; 
        }
 
        [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", CallingConvention = CallingConvention.Cdecl)] 
        private extern static SafeCFCreateRuleHandle CFTimeZoneCopyDefault();
 
        [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", CallingConvention = CallingConvention.Cdecl)]
        private extern static SafeCFGetRuleHandle CFTimeZoneGetData(SafeCFHandle tz);

        [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", CallingConvention = CallingConvention.Cdecl)] 
        private extern static void CFDataGetBytes(SafeCFHandle theData, CFRange range, [Out] byte[] buffer);
 
        [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", CallingConvention = CallingConvention.Cdecl)] 
        private extern static int CFDataGetLength(SafeCFHandle theData);
 
        private struct CFRange {
            int location;
            int length;
 
            public CFRange(int location, int length) {
                this.location = location; 
                this.length = length; 
            }
        } 
#endif // FEATURE_CORECLR
    } // TimezoneInfo
} // namespace System

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK