/// <summary>
        /// Reads an <see cref="DateTimeZone" /> value from the stream.
        /// </summary>
        /// <remarks>
        /// The value must have been written by <see cref="LegacyDateTimeZoneWriter.WriteTimeZone" />.
        /// </remarks>
        /// <returns>The <see cref="DateTimeZone" /> value from the stream.</returns>
        public DateTimeZone ReadTimeZone(string id)
        {
            int flag = ReadByte();

            switch (flag)
            {
            case LegacyDateTimeZoneWriter.FlagTimeZoneFixed:
                return(FixedDateTimeZone.Read(this, id));

            case LegacyDateTimeZoneWriter.FlagTimeZonePrecalculated:
                return(PrecalculatedDateTimeZone.ReadLegacy(this, id));

            case LegacyDateTimeZoneWriter.FlagTimeZoneNull:
                return(null);    // Only used when reading a tail zone

            case LegacyDateTimeZoneWriter.FlagTimeZoneCached:
                return(CachedDateTimeZone.ReadLegacy(this, id));

            case LegacyDateTimeZoneWriter.FlagTimeZoneDst:
                return(DaylightSavingsDateTimeZone.ReadLegacy(this, id));

            default:
                throw new InvalidNodaDataException("Unknown time zone flag type: " + flag);
            }
        }
示例#2
0
 /// <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)
         });
示例#3
0
        /// <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);
                }
            }
        }
        /// <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);
        }
示例#5
0
 public void ForZone_AlreadyCached()
 {
     Assert.AreSame(timeZone, CachedDateTimeZone.ForZone(timeZone));
 }
示例#6
0
        public void ForZone_Fixed()
        {
            var zone = DateTimeZone.ForOffset(Offset.FromHours(1));

            Assert.AreSame(zone, CachedDateTimeZone.ForZone(zone));
        }