Exemple #1
0
        internal static DateTimeZone ReadLegacy(LegacyDateTimeZoneReader reader, string id)
        {
            Preconditions.CheckNotNull(reader, "reader");
            Offset         offset = reader.ReadOffset();
            ZoneRecurrence start  = ZoneRecurrence.ReadLegacy(reader);
            ZoneRecurrence end    = ZoneRecurrence.ReadLegacy(reader);

            return(new DaylightSavingsDateTimeZone(id, offset, start, end));
        }
Exemple #2
0
        /// <summary>
        /// Converts the two adjustment rules in <paramref name="rule"/> into two ZoneRecurrences,
        /// storing them in the out parameters.
        /// </summary>
        private static void GetRecurrences(TimeZoneInfo zone, TimeZoneInfo.AdjustmentRule rule,
                                           out ZoneRecurrence standardRecurrence, out ZoneRecurrence daylightRecurrence)
        {
            int            startYear      = rule.DateStart.Year == 1 ? int.MinValue : rule.DateStart.Year;
            int            endYear        = rule.DateEnd.Year == 9999 ? int.MaxValue : rule.DateEnd.Year;
            Offset         daylightOffset = Offset.FromTimeSpan(rule.DaylightDelta);
            ZoneYearOffset daylightStart  = ConvertTransition(rule.DaylightTransitionStart);
            ZoneYearOffset daylightEnd    = ConvertTransition(rule.DaylightTransitionEnd);

            standardRecurrence = new ZoneRecurrence(zone.StandardName, Offset.Zero, daylightEnd, startYear, endYear);
            daylightRecurrence = new ZoneRecurrence(zone.DaylightName, daylightOffset, daylightStart, startYear, endYear);
        }
        internal static StandardDaylightAlternatingMap Read(IDateTimeZoneReader reader)
        {
            Preconditions.CheckNotNull(reader, nameof(reader));
            Offset         standardOffset     = reader.ReadOffset();
            string         standardName       = reader.ReadString();
            ZoneYearOffset standardYearOffset = ZoneYearOffset.Read(reader);
            string         daylightName       = reader.ReadString();
            ZoneYearOffset daylightYearOffset = ZoneYearOffset.Read(reader);
            Offset         savings            = reader.ReadOffset();
            ZoneRecurrence standardRecurrence = new ZoneRecurrence(standardName, Offset.Zero, standardYearOffset, int.MinValue, int.MaxValue);
            ZoneRecurrence dstRecurrence      = new ZoneRecurrence(daylightName, savings, daylightYearOffset, int.MinValue, int.MaxValue);

            return(new StandardDaylightAlternatingMap(standardOffset, standardRecurrence, dstRecurrence));
        }
Exemple #4
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>
        /// Returns the transition occurring strictly after the specified instant. The <paramref name="recurrence"/>
        /// parameter will be populated with the recurrence the transition goes *from*.
        /// </summary>
        /// <param name="instant">The instant after which to consider transitions.</param>
        /// <param name="recurrence">Receives the savings offset for the transition.</param>
        private Transition NextTransition(Instant instant, out ZoneRecurrence recurrence)
        {
            // Both recurrences are infinite, so they'll both have next transitions (possibly at infinity).
            Transition dstTransition             = dstRecurrence.NextOrFail(instant, standardOffset, Offset.Zero);
            Transition standardTransition        = standardRecurrence.NextOrFail(instant, standardOffset, dstRecurrence.Savings);
            var        standardTransitionInstant = standardTransition.Instant;
            var        dstTransitionInstant      = dstTransition.Instant;

            if (standardTransitionInstant < dstTransitionInstant)
            {
                // Next transition is from DST to standard.
                recurrence = dstRecurrence;
                return(standardTransition);
            }
            else if (standardTransitionInstant > dstTransitionInstant)
            {
                // Next transition is from standard to DST.
                recurrence = standardRecurrence;
                return(dstTransition);
            }
            else
            {
                // Okay, the transitions happen at the same time. If they're not at infinity, we're stumped.
                if (standardTransitionInstant.IsValid)
                {
                    throw new InvalidOperationException("Zone recurrence rules have identical transitions. This time zone is broken.");
                }
                // Okay, the two transitions must be to the end of time. Find which recurrence has the later *previous* transition...
                var previousDstTransition      = dstRecurrence.PreviousOrSameOrFail(instant, standardOffset, Offset.Zero);
                var previousStandardTransition = standardRecurrence.PreviousOrSameOrFail(instant, standardOffset, dstRecurrence.Savings);
                // No point in checking for equality here... they can't go back from the end of time to the start...
                if (previousDstTransition.Instant > previousStandardTransition.Instant)
                {
                    // The previous transition is from standard to DST. Therefore the next one is from DST to standard.
                    recurrence = dstRecurrence;
                    return(standardTransition);
                }
                else
                {
                    // The previous transition is from DST to standard. Therefore the next one is from standard to DST.
                    recurrence = standardRecurrence;
                    return(dstTransition);
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="StandardDaylightAlternatingMap"/> class.
        /// </summary>
        /// <remarks>
        /// At least one of the recurrences (it doesn't matter which) must be a "standard", i.e. not have any savings
        /// applied. The other may still not have any savings (e.g. for America/Resolute) or (for BCL compatibility) may
        /// even have negative daylight savings.
        /// </remarks>
        /// <param name="standardOffset">The standard offset.</param>
        /// <param name="startRecurrence">The start recurrence.</param>
        /// <param name="endRecurrence">The end recurrence.</param>
        internal StandardDaylightAlternatingMap(Offset standardOffset, ZoneRecurrence startRecurrence, ZoneRecurrence endRecurrence)
        {
            this.standardOffset = standardOffset;
            // Treat the recurrences as if they extended to the start of time.
            startRecurrence = startRecurrence.ToStartOfTime();
            endRecurrence   = endRecurrence.ToStartOfTime();
            Preconditions.CheckArgument(startRecurrence.IsInfinite, nameof(startRecurrence), "Start recurrence must extend to the end of time");
            Preconditions.CheckArgument(endRecurrence.IsInfinite, nameof(endRecurrence), "End recurrence must extend to the end of time");
            var dst      = startRecurrence;
            var standard = endRecurrence;

            if (startRecurrence.Savings == Offset.Zero)
            {
                dst      = endRecurrence;
                standard = startRecurrence;
            }
            Preconditions.CheckArgument(standard.Savings == Offset.Zero, nameof(startRecurrence), "At least one recurrence must not have savings applied");
            dstRecurrence      = dst;
            standardRecurrence = standard;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DaylightSavingsDateTimeZone"/> class.
        /// </summary>
        /// <remarks>
        /// At least one of the recurrences (it doesn't matter which) must be a "standard", i.e. not have any savings
        /// applied. The other may still not have any savings (e.g. for America/Resolute) or (for BCL compatibility) may
        /// even have negative daylight savings.
        /// </remarks>
        /// <param name="id">The id.</param>
        /// <param name="standardOffset">The standard offset.</param>
        /// <param name="startRecurrence">The start recurrence.</param>
        /// <param name="endRecurrence">The end recurrence.</param>
        internal DaylightSavingsDateTimeZone([NotNull] String id, Offset standardOffset, ZoneRecurrence startRecurrence, ZoneRecurrence endRecurrence)
            : base(id, false,
                   standardOffset + Offset.Min(startRecurrence.Savings, endRecurrence.Savings),
                   standardOffset + Offset.Max(startRecurrence.Savings, endRecurrence.Savings))
        {
            this.standardOffset = standardOffset;
            // Treat the recurrences as if they extended to the start of time.
            startRecurrence = startRecurrence.ToStartOfTime();
            endRecurrence   = endRecurrence.ToStartOfTime();
            Preconditions.CheckArgument(startRecurrence.IsInfinite, nameof(startRecurrence), "Start recurrence must extend to the end of time");
            Preconditions.CheckArgument(endRecurrence.IsInfinite, nameof(endRecurrence), "End recurrence must extend to the end of time");
            var dst      = startRecurrence;
            var standard = endRecurrence;

            if (startRecurrence.Savings == Offset.Zero)
            {
                dst      = endRecurrence;
                standard = startRecurrence;
            }
            Preconditions.CheckArgument(standard.Savings == Offset.Zero, nameof(startRecurrence), "At least one recurrence must not have savings applied");
            dstRecurrence      = dst;
            standardRecurrence = standard;
        }