Beispiel #1
0
            internal static BclAdjustmentRule FromWindowsAdjustmentRule(TimeZoneInfo zone, TimeZoneInfo.AdjustmentRule rule)
            {
                // With .NET 4.6, adjustment rules can have their own standard offsets, allowing
                // a much more reasonable set of time zone data. Unfortunately, this isn't directly
                // exposed, but we can detect it by just finding the UTC offset for an arbitrary
                // time within the rule - the start, in this case - and then take account of the
                // possibility of that being in daylight saving time. Fortunately, we only need
                // to do this during the setup.
                var ruleStandardOffset = zone.GetUtcOffset(rule.DateStart);

                if (zone.IsDaylightSavingTime(rule.DateStart))
                {
                    ruleStandardOffset -= rule.DaylightDelta;
                }
                var standardOffset = ruleStandardOffset.ToOffset();

                // Although the rule may have its own standard offset, the start/end is still determined
                // using the zone's standard offset.
                var zoneStandardOffset = zone.BaseUtcOffset.ToOffset();

                // Note: this extends back from DateTime.MinValue to start of time, even though the BCL can represent
                // as far back as 1AD. This is in the *spirit* of a rule which goes back that far.
                var start = rule.DateStart == DateTime.MinValue ? Instant.BeforeMinValue : rule.DateStart.ToLocalDateTime().WithOffset(zoneStandardOffset).ToInstant();
                // The end instant (exclusive) is the end of the given date, so we need to add a day.
                var end     = rule.DateEnd == MaxDate ? Instant.AfterMaxValue : rule.DateEnd.ToLocalDateTime().PlusDays(1).WithOffset(zoneStandardOffset).ToInstant();
                var savings = rule.DaylightDelta.ToOffset();

                PartialZoneIntervalMap partialMap;

                // Some rules have DST start/end of "January 1st", to indicate that they're just in standard time. This is important
                // for rules which have a standard offset which is different to the standard offset of the zone itself.
                if (IsStandardOffsetOnlyRule(rule))
                {
                    partialMap = PartialZoneIntervalMap.ForZoneInterval(zone.StandardName, start, end, standardOffset, Offset.Zero);
                }
                else
                {
                    var daylightRecurrence        = new ZoneRecurrence(zone.DaylightName, savings, ConvertTransition(rule.DaylightTransitionStart), int.MinValue, int.MaxValue);
                    var standardRecurrence        = new ZoneRecurrence(zone.StandardName, Offset.Zero, ConvertTransition(rule.DaylightTransitionEnd), int.MinValue, int.MaxValue);
                    IZoneIntervalMap recurringMap = new StandardDaylightAlternatingMap(standardOffset, standardRecurrence, daylightRecurrence);
                    // Fake 1 hour savings if the adjustment rule claims to be 0 savings. See DaylightFakingZoneIntervalMap documentation below for more details.
                    if (savings == Offset.Zero)
                    {
                        recurringMap = new DaylightFakingZoneIntervalMap(recurringMap, zone.DaylightName);
                    }
                    partialMap = new PartialZoneIntervalMap(start, end, recurringMap);
                }
                return(new BclAdjustmentRule(start, end, standardOffset, savings, partialMap));
            }
        /// <summary>
        /// Reads a time zone from the specified reader.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="id">The id.</param>
        /// <returns>The time zone.</returns>
        internal static DateTimeZone Read([Trusted][NotNull] IDateTimeZoneReader reader, [Trusted][NotNull] string id)
        {
            Preconditions.DebugCheckNotNull(reader, nameof(reader));
            Preconditions.DebugCheckNotNull(id, nameof(id));
            int size    = reader.ReadCount();
            var periods = new ZoneInterval[size];
            // It's not entirely clear why we don't just assume that the first zone interval always starts at Instant.BeforeMinValue
            // (given that we check that later) but we don't... and changing that now could cause compatibility issues.
            var start = reader.ReadZoneIntervalTransition(null);

            for (int i = 0; i < size; i++)
            {
                var name      = reader.ReadString();
                var offset    = reader.ReadOffset();
                var savings   = reader.ReadOffset();
                var nextStart = reader.ReadZoneIntervalTransition(start);
                periods[i] = new ZoneInterval(name, start, nextStart, offset, savings);
                start      = nextStart;
            }
            var tailZone = reader.ReadByte() == 1 ? StandardDaylightAlternatingMap.Read(reader) : null;

            return(new PrecalculatedDateTimeZone(id, periods, tailZone));
        }