예제 #1
0
        /// <summary>
        /// Creates a new <see cref="BclDateTimeZone" /> from a <see cref="TimeZoneInfo"/> from the Base Class Library.
        /// </summary>
        /// <param name="bclZone">The original time zone to take information from.</param>
        /// <returns>A <see cref="BclDateTimeZone"/> wrapping the given <c>TimeZoneInfo</c>.</returns>
        public static BclDateTimeZone FromTimeZoneInfo(TimeZoneInfo bclZone)
        {
            Preconditions.CheckNotNull(bclZone, nameof(bclZone));
            Offset standardOffset = bclZone.BaseUtcOffset.ToOffset();
            var    rules          = bclZone.GetAdjustmentRules();

            if (!bclZone.SupportsDaylightSavingTime || rules.Length == 0)
            {
                var fixedInterval = new ZoneInterval(bclZone.StandardName, Instant.BeforeMinValue, Instant.AfterMaxValue, standardOffset, Offset.Zero);
                return(new BclDateTimeZone(bclZone, standardOffset, standardOffset, new SingleZoneIntervalMap(fixedInterval)));
            }

            int windowsRules  = rules.Count(IsWindowsRule);
            var ruleConverter = AreWindowsStyleRules(rules)
                ? rule => BclAdjustmentRule.FromWindowsAdjustmentRule(bclZone, rule)
                : (Converter <TimeZoneInfo.AdjustmentRule, BclAdjustmentRule>)(rule => BclAdjustmentRule.FromUnixAdjustmentRule(bclZone, rule));

            BclAdjustmentRule[] convertedRules = Array.ConvertAll(rules, ruleConverter);

            Offset minRuleOffset = convertedRules.Aggregate(Offset.MaxValue, (min, rule) => Offset.Min(min, rule.Savings + rule.StandardOffset));
            Offset maxRuleOffset = convertedRules.Aggregate(Offset.MinValue, (min, rule) => Offset.Max(min, rule.Savings + rule.StandardOffset));

            IZoneIntervalMap uncachedMap = BuildMap(convertedRules, standardOffset, bclZone.StandardName);
            IZoneIntervalMap cachedMap   = CachingZoneIntervalMap.CacheMap(uncachedMap);

            return(new BclDateTimeZone(bclZone, Offset.Min(standardOffset, minRuleOffset), Offset.Max(standardOffset, maxRuleOffset), cachedMap));
        }
예제 #2
0
        /// <summary>
        /// Creates a new <see cref="BclDateTimeZone" /> from a <see cref="TimeZoneInfo"/> from the Base Class Library.
        /// </summary>
        /// <param name="bclZone">The original time zone to take information from.</param>
        /// <returns>A <see cref="BclDateTimeZone"/> wrapping the given <c>TimeZoneInfo</c>.</returns>
        public static BclDateTimeZone FromTimeZoneInfo(TimeZoneInfo bclZone)
        {
            Preconditions.CheckNotNull(bclZone, nameof(bclZone));
            Offset standardOffset = bclZone.BaseUtcOffset.ToOffset();
            var    rules          = bclZone.GetAdjustmentRules();

            if (!bclZone.SupportsDaylightSavingTime || rules.Length == 0)
            {
                var fixedInterval = new ZoneInterval(bclZone.StandardName, Instant.BeforeMinValue, Instant.AfterMaxValue, standardOffset, Offset.Zero);
                return(new BclDateTimeZone(bclZone, new SingleZoneIntervalMap(fixedInterval)));
            }

            BclAdjustmentRule[] convertedRules;
            if (AreWindowsStyleRules(rules))
            {
                convertedRules = Array.ConvertAll(rules, rule => BclAdjustmentRule.FromWindowsAdjustmentRule(bclZone, rule));
            }
            else
            {
                convertedRules = Array.ConvertAll(rules, rule => BclAdjustmentRule.FromUnixAdjustmentRule(bclZone, rule));
                FixUnixTransitions(convertedRules);
            }

            IZoneIntervalMap uncachedMap = BuildMap(convertedRules, standardOffset, bclZone.StandardName);
            IZoneIntervalMap cachedMap   = CachingZoneIntervalMap.CacheMap(uncachedMap);

            return(new BclDateTimeZone(bclZone, cachedMap));
        }
예제 #3
0
        private static IZoneIntervalMap BuildMap(BclAdjustmentRule[] rules, Offset standardOffset, [NotNull] string standardName)
        {
            Preconditions.CheckNotNull(standardName, nameof(standardName));

            // First work out a naive list of partial maps. These will give the right offset at every instant, but not necessarily
            // correct intervals - we may we need to stitch intervals together.
            List<PartialZoneIntervalMap> maps = new List<PartialZoneIntervalMap>();
            // Handle the start of time until the start of the first rule, if necessary.
            if (rules[0].Start.IsValid)
            {
                maps.Add(PartialZoneIntervalMap.ForZoneInterval(standardName, Instant.BeforeMinValue, rules[0].Start, standardOffset, Offset.Zero));
            }
            for (int i = 0; i < rules.Length - 1; i++)
            {
                var beforeRule = rules[i];
                var afterRule = rules[i + 1];
                maps.Add(beforeRule.PartialMap);
                // If there's a gap between this rule and the next one, fill it with a fixed interval.
                if (beforeRule.End < afterRule.Start)
                {
                    maps.Add(PartialZoneIntervalMap.ForZoneInterval(standardName, beforeRule.End, afterRule.Start, standardOffset, Offset.Zero));
                }
            }

            var lastRule = rules[rules.Length - 1];
            maps.Add(lastRule.PartialMap);

            // Handle the end of the last rule until the end of time, if necessary.
            if (lastRule.End.IsValid)
            {
                maps.Add(PartialZoneIntervalMap.ForZoneInterval(standardName, lastRule.End, Instant.AfterMaxValue, standardOffset, Offset.Zero));
            }
            return PartialZoneIntervalMap.ConvertToFullMap(maps);
        }