Beispiel #1
0
        internal static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(ref TIME_ZONE_INFORMATION timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset)
        {
            bool supportsDst = (timeZoneInformation.StandardDate.wMonth != 0);

            if (!supportsDst)
            {
                if (timeZoneInformation.Bias == defaultBaseUtcOffset)
                {
                    // this rule will not contain any information to be used to adjust dates. just ignore it
                    return(null);
                }

                return(AdjustmentRule.CreateAdjustmentRule(
                           startDate,
                           endDate,
                           TimeSpan.Zero, // no daylight saving transition
                           TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1),
                           TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1),
                           new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule
                           noDaylightTransitions: false));
            }

            //
            // 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);
            }

            return(AdjustmentRule.CreateAdjustmentRule(
                       startDate,
                       endDate,
                       new TimeSpan(0, -timeZoneInformation.DaylightBias, 0),
                       (TransitionTime)daylightTransitionStart,
                       (TransitionTime)daylightTransitionEnd,
                       new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0),
                       noDaylightTransitions: false));
        }
Beispiel #2
0
        //
        // TransitionTimeFromTimeZoneInformation -
        //
        // Converts a TimeZoneInformation (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
        //
        private static bool TransitionTimeFromTimeZoneInformation(TIME_ZONE_INFORMATION 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.wMonth != 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.wYear == 0)
                {
                    transitionTime = TransitionTime.CreateFloatingDateRule(
                        new DateTime(1,                 /* year  */
                                     1,                 /* month */
                                     1,                 /* day   */
                                     timeZoneInformation.DaylightDate.wHour,
                                     timeZoneInformation.DaylightDate.wMinute,
                                     timeZoneInformation.DaylightDate.wSecond,
                                     timeZoneInformation.DaylightDate.wMilliseconds),
                        timeZoneInformation.DaylightDate.wMonth,
                        timeZoneInformation.DaylightDate.wDay,                /* Week 1-5 */
                        (DayOfWeek)timeZoneInformation.DaylightDate.wDayOfWeek);
                }
                else
                {
                    transitionTime = TransitionTime.CreateFixedDateRule(
                        new DateTime(1,                 /* year  */
                                     1,                 /* month */
                                     1,                 /* day   */
                                     timeZoneInformation.DaylightDate.wHour,
                                     timeZoneInformation.DaylightDate.wMinute,
                                     timeZoneInformation.DaylightDate.wSecond,
                                     timeZoneInformation.DaylightDate.wMilliseconds),
                        timeZoneInformation.DaylightDate.wMonth,
                        timeZoneInformation.DaylightDate.wDay);
                }
            }
            else
            {
                //
                // read the "daylightTransitionEnd"
                //
                if (timeZoneInformation.StandardDate.wYear == 0)
                {
                    transitionTime = TransitionTime.CreateFloatingDateRule(
                        new DateTime(1,                 /* year  */
                                     1,                 /* month */
                                     1,                 /* day   */
                                     timeZoneInformation.StandardDate.wHour,
                                     timeZoneInformation.StandardDate.wMinute,
                                     timeZoneInformation.StandardDate.wSecond,
                                     timeZoneInformation.StandardDate.wMilliseconds),
                        timeZoneInformation.StandardDate.wMonth,
                        timeZoneInformation.StandardDate.wDay,                /* Week 1-5 */
                        (DayOfWeek)timeZoneInformation.StandardDate.wDayOfWeek);
                }
                else
                {
                    transitionTime = TransitionTime.CreateFixedDateRule(
                        new DateTime(1,                 /* year  */
                                     1,                 /* month */
                                     1,                 /* day   */
                                     timeZoneInformation.StandardDate.wHour,
                                     timeZoneInformation.StandardDate.wMinute,
                                     timeZoneInformation.StandardDate.wSecond,
                                     timeZoneInformation.StandardDate.wMilliseconds),
                        timeZoneInformation.StandardDate.wMonth,
                        timeZoneInformation.StandardDate.wDay);
                }
            }

            return(true);
        }
Beispiel #3
0
        private static TimeZoneInfoResult TryGetFullTimeZoneInformation(TimeZoneInformation timeZoneInformation, out TimeZoneInfo value, out Exception e, int defaultBaseUtcOffset)
        {
            uint           firstYear, lastYear;
            AdjustmentRule rule;

            AdjustmentRule[] zoneRules = null;

            value = null;
            e     = null;

            //
            // First get the adjustment rules
            //

            if (Interop.mincore.GetDynamicTimeZoneInformationEffectiveYears(ref timeZoneInformation.Dtzi, out firstYear, out lastYear) != 0)
            {
                rule = CreateAdjustmentRuleFromTimeZoneInformation(timeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
                if (rule != null)
                {
                    zoneRules = new AdjustmentRule[1] {
                        rule
                    };
                }
            }
            else
            {
                if (firstYear == lastYear)
                {
                    // there is just 1 dynamic rule for this time zone.
                    rule = CreateAdjustmentRuleFromTimeZoneInformation(timeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
                    if (rule != null)
                    {
                        zoneRules = new AdjustmentRule[1] {
                            rule
                        };
                    }
                }
                else
                {
                    TIME_ZONE_INFORMATION         tzdi  = new TIME_ZONE_INFORMATION();
                    LowLevelList <AdjustmentRule> rules = new LowLevelList <AdjustmentRule>();

                    //
                    // First rule
                    //

                    if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)firstYear, ref timeZoneInformation.Dtzi, out tzdi))
                    {
                        return(TimeZoneInfoResult.InvalidTimeZoneException);
                    }
                    rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, DateTime.MinValue.Date, new DateTime((int)firstYear, 12, 31), defaultBaseUtcOffset);
                    if (rule != null)
                    {
                        rules.Add(rule);
                    }

                    for (uint i = firstYear + 1; i < lastYear; i++)
                    {
                        if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)i, ref timeZoneInformation.Dtzi, out tzdi))
                        {
                            return(TimeZoneInfoResult.InvalidTimeZoneException);
                        }
                        rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, new DateTime((int)i, 1, 1), new DateTime((int)i, 12, 31), defaultBaseUtcOffset);
                        if (rule != null)
                        {
                            rules.Add(rule);
                        }
                    }

                    //
                    // Last rule
                    //

                    if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)lastYear, ref timeZoneInformation.Dtzi, out tzdi))
                    {
                        return(TimeZoneInfoResult.InvalidTimeZoneException);
                    }
                    rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, new DateTime((int)lastYear, 1, 1), DateTime.MaxValue.Date, defaultBaseUtcOffset);
                    if (rule != null)
                    {
                        rules.Add(rule);
                    }

                    if (rules.Count > 0)
                    {
                        zoneRules = rules.ToArray();
                    }
                }
            }

            //
            // Create TimeZoneInfo object
            //
            try
            {
                // Note that all names we have are localized names as Windows always return the localized names
                value = new TimeZoneInfo(
                    timeZoneInformation.TimeZoneKeyName,
                    new TimeSpan(0, -(timeZoneInformation.Dtzi.Bias), 0),
                    timeZoneInformation.StandardName,   // we use the display name as the standared names
                    timeZoneInformation.StandardName,
                    timeZoneInformation.DaylightName,
                    zoneRules,
                    false);

                return(System.TimeZoneInfo.TimeZoneInfoResult.Success);
            }
            catch (ArgumentException ex)
            {
                // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException
                value = null;
                e     = ex;
                return(System.TimeZoneInfo.TimeZoneInfoResult.InvalidTimeZoneException);
            }
            catch (InvalidTimeZoneException ex)
            {
                // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException
                value = null;
                e     = ex;
                return(System.TimeZoneInfo.TimeZoneInfoResult.InvalidTimeZoneException);
            }
        }
Beispiel #4
0
 //
 // TryCompareStandardDate -
 //
 // Helper function that compares the StandardBias and StandardDate portion a
 // TimeZoneInformation struct to a time zone registry entry
 //
 private static Boolean TryCompareStandardDate(TIME_ZONE_INFORMATION timeZone, REGISTRY_TIME_ZONE_INFORMATION registryTimeZoneInfo)
 {
     return timeZone.Bias == registryTimeZoneInfo.Bias
            && timeZone.StandardBias == registryTimeZoneInfo.StandardBias
            && timeZone.StandardDate.wYear == registryTimeZoneInfo.StandardDate.wYear
            && timeZone.StandardDate.wMonth == registryTimeZoneInfo.StandardDate.wMonth
            && timeZone.StandardDate.wDayOfWeek == registryTimeZoneInfo.StandardDate.wDayOfWeek
            && timeZone.StandardDate.wDay == registryTimeZoneInfo.StandardDate.wDay
            && timeZone.StandardDate.wHour == registryTimeZoneInfo.StandardDate.wHour
            && timeZone.StandardDate.wMinute == registryTimeZoneInfo.StandardDate.wMinute
            && timeZone.StandardDate.wSecond == registryTimeZoneInfo.StandardDate.wSecond
            && timeZone.StandardDate.wMilliseconds == registryTimeZoneInfo.StandardDate.wMilliseconds;
 }
Beispiel #5
0
        //
        // TryCompareTimeZoneInformationToRegistry -
        //
        // Helper function that compares a TimeZoneInformation struct to a time zone registry entry
        //
        static unsafe private Boolean TryCompareTimeZoneInformationToRegistry(TIME_ZONE_INFORMATION timeZone, string id, out Boolean dstDisabled)
        {
            dstDisabled = false;
            using (RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(
                                  c_timeZonesRegistryHive + "\\" + id,
                                  false
                                  ))
            {
                if (key == null)
                {
                    return false;
                }

                REGISTRY_TIME_ZONE_INFORMATION registryTimeZoneInfo;
                Byte[] regValue = (Byte[])key.GetValue(c_timeZoneInfoValue, null, RegistryValueOptions.None) as Byte[];
                if (regValue == null || regValue.Length != c_regByteLength) return false;
                registryTimeZoneInfo = new REGISTRY_TIME_ZONE_INFORMATION(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;
                }

                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.wYear == registryTimeZoneInfo.DaylightDate.wYear
                            && timeZone.DaylightDate.wMonth == registryTimeZoneInfo.DaylightDate.wMonth
                            && timeZone.DaylightDate.wDayOfWeek == registryTimeZoneInfo.DaylightDate.wDayOfWeek
                            && timeZone.DaylightDate.wDay == registryTimeZoneInfo.DaylightDate.wDay
                            && timeZone.DaylightDate.wHour == registryTimeZoneInfo.DaylightDate.wHour
                            && timeZone.DaylightDate.wMinute == registryTimeZoneInfo.DaylightDate.wMinute
                            && timeZone.DaylightDate.wSecond == registryTimeZoneInfo.DaylightDate.wSecond
                            && timeZone.DaylightDate.wMilliseconds == registryTimeZoneInfo.DaylightDate.wMilliseconds);

                // 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, new String(timeZone.StandardName), StringComparison.Ordinal) == 0;
                }
                return result;
            }
        }
Beispiel #6
0
        //
        // GetLocalTimeZoneFromWin32Data -
        //
        // Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of
        // try/catch logic for handling the TimeZoneInfo private constructor that takes
        // a TIME_ZONE_INFORMATION structure.
        //
        private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(TIME_ZONE_INFORMATION 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);
        }
Beispiel #7
0
        //
        // GetLocalTimeZone -
        //
        // Helper function for retrieving the local system time zone.
        //
        // returns a new TimeZoneInfo instance
        //
        // may throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException
        //
        // assumes cachedData lock is taken
        //
        static unsafe private TimeZoneInfo GetLocalTimeZone(CachedData cachedData)
        {
            String id = null;

            //
            // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id"
            //
            Interop.mincore.TIME_DYNAMIC_ZONE_INFORMATION dynamicTimeZoneInformation =
                new Interop.mincore.TIME_DYNAMIC_ZONE_INFORMATION();

            // call kernel32!GetDynamicTimeZoneInformation...
            long result = Interop.mincore.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation);
            if (result == Interop.mincore.TIME_ZONE_ID_INVALID)
            {
                // return a dummy entry
                return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);
            }

            TIME_ZONE_INFORMATION timeZoneInformation =
                new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation);

            Boolean dstDisabled = dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0;

            // check to see if we can use the key name returned from the API call
            if (!String.IsNullOrEmpty(new String(dynamicTimeZoneInformation.TimeZoneKeyName)))
            {
                TimeZoneInfo zone;
                Exception ex;

                if (TryGetTimeZone(new String(dynamicTimeZoneInformation.TimeZoneKeyName), dstDisabled, out zone, out ex, cachedData) == 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                
            id = FindIdFromTimeZoneInformation(timeZoneInformation, out dstDisabled);

            if (id != null)
            {
                TimeZoneInfo zone;
                Exception ex;
                if (TryGetTimeZone(id, dstDisabled, out zone, out ex, cachedData) == 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);
        }
Beispiel #8
0
        //
        // FindIdFromTimeZoneInformation -
        //
        // Helper function that searches the registry for a time zone entry
        // that matches the TimeZoneInformation struct
        //
        private static String FindIdFromTimeZoneInformation(TIME_ZONE_INFORMATION timeZone, out Boolean dstDisabled)
        {
            dstDisabled = false;

            using (RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(
                              c_timeZonesRegistryHive,
                              false
                              ))
            {
                if (key == null)
                {
                    return null;
                }
                foreach (string keyName in key.GetSubKeyNames())
                {
                    if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled))
                    {
                        return keyName;
                    }
                }
            }
            return null;
        }
Beispiel #9
0
        // ----- SECTION: internal static utility methods ----------------*

        //
        // 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".
        //
        private static Boolean CheckDaylightSavingTimeNotSupported(TIME_ZONE_INFORMATION timeZone)
        {
            return (timeZone.DaylightDate.wYear == timeZone.StandardDate.wYear
                    && timeZone.DaylightDate.wMonth == timeZone.StandardDate.wMonth
                    && timeZone.DaylightDate.wDayOfWeek == timeZone.StandardDate.wDayOfWeek
                    && timeZone.DaylightDate.wDay == timeZone.StandardDate.wDay
                    && timeZone.DaylightDate.wHour == timeZone.StandardDate.wHour
                    && timeZone.DaylightDate.wMinute == timeZone.StandardDate.wMinute
                    && timeZone.DaylightDate.wSecond == timeZone.StandardDate.wSecond
                    && timeZone.DaylightDate.wMilliseconds == timeZone.StandardDate.wMilliseconds);
        }
Beispiel #10
0
        // -------- SECTION: constructors -----------------*
        // 
        // TimeZoneInfo -
        //
        // private ctor
        //
        private unsafe TimeZoneInfo(TIME_ZONE_INFORMATION zone, Boolean dstDisabled)
        {
            if (String.IsNullOrEmpty(new String(zone.StandardName)))
            {
                _id = c_localId;  // the ID must contain at least 1 character - initialize _id to "Local"
            }
            else
            {
                _id = new String(zone.StandardName);
            }
            _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0);

            if (!dstDisabled)
            {
                // only create the adjustment rule if DST is enabled
                REGISTRY_TIME_ZONE_INFORMATION regZone = new REGISTRY_TIME_ZONE_INFORMATION(zone);
                AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias);
                if (rule != null)
                {
                    _adjustmentRules = new AdjustmentRule[1];
                    _adjustmentRules[0] = rule;
                }
            }

            ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime);
            _displayName = new String(zone.StandardName);
            _standardDisplayName = new String(zone.StandardName);
            _daylightDisplayName = new String(zone.DaylightName);
        }