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