/// <inheritdoc />
 [NotNull] public DateTimeZone ForId([NotNull] string id)
 {
     if (!CanonicalIdMap.TryGetValue(Preconditions.CheckNotNull(id, nameof(id)), out string canonicalId))
     {
         throw new ArgumentException("Time zone with ID " + id + " not found in source " + version, nameof(id));
     }
     return(source.CreateZone(id, canonicalId));
 }
        /// <summary>
        /// Validates that the data within this source is consistent with itself.
        /// </summary>
        /// <remarks>
        /// Source data is not validated automatically when it's loaded, but any source
        /// loaded from data produced by <c>NodaTime.TzdbCompiler</c> (including the data shipped with Noda Time)
        /// will already have been validated via this method when it was originally produced. This method should
        /// only normally be called explicitly if you have data from a source you're unsure of.
        /// </remarks>
        /// <exception cref="InvalidNodaDataException">The source data is invalid. The source may not function
        /// correctly.</exception>
        public void Validate()
        {
            // Check that each entry has a canonical value. (Every mapping x to y
            // should be such that y maps to itself.)
            foreach (var entry in this.CanonicalIdMap)
            {
                string canonical;
                if (!CanonicalIdMap.TryGetValue(entry.Value, out canonical))
                {
                    throw new InvalidNodaDataException(
                              "Mapping for entry {entry.Key} ({entry.Value}) is missing");
                }
                if (entry.Value != canonical)
                {
                    throw new InvalidNodaDataException(
                              "Mapping for entry {entry.Key} ({entry.Value}) is not canonical ({entry.Value} maps to {canonical}");
                }
            }

            // Check that every Windows mapping has a primary territory
            foreach (var mapZone in source.WindowsMapping.MapZones)
            {
                // Simplest way of checking is to find the primary mapping...
                if (!source.WindowsMapping.PrimaryMapping.ContainsKey(mapZone.WindowsId))
                {
                    throw new InvalidNodaDataException(
                              $"Windows mapping for standard ID {mapZone.WindowsId} has no primary territory");
                }
            }

            // Check that each Windows mapping has a known canonical ID.
            foreach (var mapZone in source.WindowsMapping.MapZones)
            {
                foreach (var id in mapZone.TzdbIds)
                {
                    if (!CanonicalIdMap.ContainsKey(id))
                    {
                        throw new InvalidNodaDataException(
                                  $"Windows mapping uses canonical ID {id} which is missing");
                    }
                }
            }

            // Check that each additional Windows standard name mapping has a known canonical ID.
            var additionalMappings = source.WindowsAdditionalStandardNameToIdMapping;

            if (additionalMappings != null)
            {
                foreach (var id in additionalMappings.Values)
                {
                    if (!CanonicalIdMap.ContainsKey(id))
                    {
                        throw new InvalidNodaDataException(
                                  $"Windows additional standard name mapping uses canonical ID {id} which is missing");
                    }
                }
            }

            // Check that each zone location has a valid zone ID
            if (ZoneLocations != null)
            {
                foreach (var location in ZoneLocations)
                {
                    if (!CanonicalIdMap.ContainsKey(location.ZoneId))
                    {
                        throw new InvalidNodaDataException(
                                  $"Zone location {location.CountryName} uses zone ID {location.ZoneId} which is missing");
                    }
                }
            }
            if (Zone1970Locations != null)
            {
                foreach (var location in Zone1970Locations)
                {
                    if (!CanonicalIdMap.ContainsKey(location.ZoneId))
                    {
                        throw new InvalidNodaDataException(
                                  $"Zone 1970 location {location.Countries[0].Name} uses zone ID {location.ZoneId} which is missing");
                    }
                }
            }
        }