public OffsetInfo(ZoneRule zone, Rule rule, DateTime cutoverDate)
 {
     _cutoverDate = cutoverDate;
     _gmtOffset = zone.GmtOffset;
     _dstOffset = rule.Save;
     _hasRule = true;
 }
        public static void LoadFromStream(TextReader sr)
        {
            // Save the default zone
            Zone lastZone = null;

            //            while (!sr.EndOfStream)
            while (true)
            {
              string s = sr.ReadLine();
              if (s == null) break;

              // Ignore comments
              if (s.Trim().StartsWith("#"))
                  continue;

              // Ignore empty lines
              if (string.IsNullOrEmpty(s.Trim()))
                  continue;

              if (s.StartsWith("Rule"))
              {
                  // We have a rule so create it and add it
                  Rule newRule = new Rule(s);
                  if (!_rules.ContainsKey(newRule.Name))
                  {
                      _rules.Add(newRule.Name, new List<Rule>());
                  }
                  _rules[newRule.Name].Add(newRule);
              }
              else if (s.StartsWith("Link"))
              {
                try
                {
                  // Clean-up the string
                  string[] arr = StripTrailingComments(s).Trim().Replace(' ', '\t').Replace("\t\t", "\t").Split('\t');

                  Debug.Assert(arr.Length >= 3 && arr.Length <= 4, "Link entry invalid with " + arr.Length.ToString() + " entries");
                  if (arr.Length == 3)
                  {
                      // This is well formed
                      if (!_links.ContainsKey(arr[2]))
                      {
                        _links.Add(arr[2], arr[1]);
                      }
                  }
                  else if (arr.Length == 4)
                  {
                      // This seems to be a standard variation on the 3 item link
                      Debug.Assert(arr[2].Length == 0);
                      if (!_links.ContainsKey(arr[3]))
                      {
                        _links.Add(arr[3], arr[1]);
                      }
                  }
                }
                catch (Exception E)
                {
                  throw new Exception(String.Format("Ошибка разбора связи '{0}': {1}", s, E.Message));
                }
              }
              else
              {
                // We have a zone
                Zone newZone = Zone.Parse(StripTrailingComments(s), lastZone);
                if (!_zones.ContainsKey(newZone.Name))
                {
                  _zones.Add(newZone.Name, newZone);
                }

                // Save this zone to reuse if the next one is empty
                lastZone = newZone;
              }
            }
        }