/// <summary> /// Creates the <see cref="DateTimeZone"/> for the given canonical ID, which will definitely /// be one of the values of the TzdbAliases dictionary. /// </summary> /// <param name="id">ID for the returned zone, which may be an alias.</param> /// <param name="canonicalId">Canonical ID for zone data</param> public DateTimeZone CreateZone(string id, string canonicalId) { Preconditions.CheckNotNull(id, nameof(id)); Preconditions.CheckNotNull(canonicalId, nameof(canonicalId)); using (var stream = zoneFields[canonicalId].CreateStream()) { var reader = new DateTimeZoneReader(stream, stringPool); // Skip over the ID before the zone data itself reader.ReadString(); var type = (DateTimeZoneWriter.DateTimeZoneType)reader.ReadByte(); return(type switch { DateTimeZoneWriter.DateTimeZoneType.Fixed => FixedDateTimeZone.Read(reader, id), DateTimeZoneWriter.DateTimeZoneType.Precalculated => CachedDateTimeZone.ForZone(PrecalculatedDateTimeZone.Read(reader, id)), _ => throw new InvalidNodaDataException("Unknown time zone type " + type) });
/// <inheritdoc /> public DateTimeZone CreateZone(string id, string canonicalId) { using (var stream = zoneFields[canonicalId].CreateStream()) { var reader = new DateTimeZoneReader(stream, stringPool); // Skip over the ID before the zone data itself reader.ReadString(); var type = (DateTimeZoneWriter.DateTimeZoneType)reader.ReadByte(); switch (type) { case DateTimeZoneWriter.DateTimeZoneType.Fixed: return(FixedDateTimeZone.Read(reader, id)); case DateTimeZoneWriter.DateTimeZoneType.Precalculated: return(CachedDateTimeZone.ForZone(PrecalculatedDateTimeZone.Read(reader, id))); default: throw new InvalidNodaDataException("Unknown time zone type " + type); } } }
public void ForZone_AlreadyCached() { Assert.AreSame(timeZone, CachedDateTimeZone.ForZone(timeZone)); }
/// <summary> /// Processes all the rules and builds a DateTimeZone. /// </summary> /// <param name="zoneId">Time zone ID to assign</param> public DateTimeZone ToDateTimeZone(String zoneId) { Preconditions.CheckNotNull(zoneId, "zoneId"); var transitions = new List <ZoneTransition>(); DateTimeZone tailZone = null; Instant instant = Instant.MinValue; int ruleSetCount = ruleSets.Count; bool tailZoneSeamValid = false; for (int i = 0; i < ruleSetCount; i++) { var ruleSet = ruleSets[i]; var transitionIterator = ruleSet.Iterator(instant); ZoneTransition nextTransition = transitionIterator.First(); if (nextTransition == null) { continue; } AddTransition(transitions, nextTransition); while ((nextTransition = transitionIterator.Next()) != null) { if (AddTransition(transitions, nextTransition)) { if (tailZone != null) { // Got the extra transition before DaylightSavingsTimeZone. // This final transition has a valid start point and offset, but // we don't know where it ends - which is fine, as the tail zone will // take over. tailZoneSeamValid = true; break; } } if (tailZone == null && i == ruleSetCount - 1) { tailZone = transitionIterator.BuildTailZone(zoneId); // If tailZone is not null, don't break out of main loop until at least one // more transition is calculated. This ensures a correct 'seam' to the // DaylightSavingsTimeZone. } } instant = ruleSet.GetUpperLimit(transitionIterator.Savings); } // Simple case where we don't have a trailing daylight saving zone. if (tailZone == null) { switch (transitions.Count) { case 0: return(new FixedDateTimeZone(zoneId, Offset.Zero)); case 1: return(new FixedDateTimeZone(zoneId, transitions[0].WallOffset)); default: var ret = CreatePrecalculatedDateTimeZone(zoneId, transitions, Instant.MaxValue, null); return(ret.IsCachable() ? CachedDateTimeZone.ForZone(ret) : ret); } } // Sanity check if (!tailZoneSeamValid) { throw new InvalidOperationException("Invalid time zone data for id " + zoneId + "; no valid transition before tail zone"); } // The final transition should not be used for a zone interval, // although it should have the same offset etc as the tail zone for its starting point. var lastTransition = transitions[transitions.Count - 1]; var firstTailZoneInterval = tailZone.GetZoneInterval(lastTransition.Instant); if (lastTransition.StandardOffset != firstTailZoneInterval.StandardOffset || lastTransition.WallOffset != firstTailZoneInterval.WallOffset || lastTransition.Savings != firstTailZoneInterval.Savings || lastTransition.Name != firstTailZoneInterval.Name) { throw new InvalidOperationException( string.Format("Invalid seam to tail zone in time zone {0}; final transition {1} different to first tail zone interval {2}", zoneId, lastTransition, firstTailZoneInterval)); } transitions.RemoveAt(transitions.Count - 1); var zone = CreatePrecalculatedDateTimeZone(zoneId, transitions, lastTransition.Instant, tailZone); return(zone.IsCachable() ? CachedDateTimeZone.ForZone(zone) : zone); }
public void ForZone_Fixed() { var zone = DateTimeZone.ForOffset(Offset.FromHours(1)); Assert.AreSame(zone, CachedDateTimeZone.ForZone(zone)); }