public OffsetInfo(ZoneRule zone) { _gmtOffset = zone.GmtOffset; _hasRule = false; _cutoverDate = DateTime.MinValue; _dstOffset = TimeSpan.Zero; }
public OffsetInfo(ZoneRule zone, Rule rule, DateTime cutoverDate) { _cutoverDate = cutoverDate; _gmtOffset = zone.GmtOffset; _dstOffset = rule.Save; _hasRule = true; }
private OffsetInfo GetDstOffset(DateTime dt, ZoneRule zone) { // Keep a handle on the best match Rule bestRule = null; DateTime cutoverDt = DateTime.MinValue; // Check to see if there are any rules for this zone if (!Database.Rules.ContainsKey(zone.RuleName)) //no rule return new OffsetInfo(zone); // There are matching rules. // Now get the exact rule // Iterate through all the rules foreach (Rule rule in Database.Rules[zone.RuleName]) { if (dt.Year >= rule.From && dt.Year <= rule.To + 1) { // This rule may be in the range DateTime newDt = DateTime.MinValue; // Try the year before if (rule.TryGetCutoverDateTime(dt.Year - 1, out newDt) && newDt > cutoverDt && newDt <= dt) //rule can take effect before or on the date { // We have a new winner cutoverDt = newDt; bestRule = rule; } // Try the current year if (rule.TryGetCutoverDateTime(dt.Year, out newDt) && newDt > cutoverDt && newDt <= dt) //rule can take effect before or on the date { // We have a new winner cutoverDt = newDt; bestRule = rule; } } } // Return the right one if (bestRule == null) return new OffsetInfo(zone); return new OffsetInfo(zone, bestRule, cutoverDt); }
/// <summary> /// Creates a zone based on a text string /// </summary> /// <param name="line">A given rule line from the zone file</param> /// <param name="defaultZone">The default zone to use if not specified in the line</param> /// <remarks> /// The format of each line is: /// Zone NAME GMTOFF RULES FORMAT [UNTIL] /// /// Zones can appear in sequential lines in the file /// and in this case the zone information from the previous line /// is carried on. /// /// Note: The format of the file seems pretty inconsistent /// so this function is not as elegant as it could be. /// </remarks> public static Zone Parse(string line, Zone defaultZone) { // Create the zone we will be returning Zone zone = null; DateTime Since; // Split up the line string[] arr = Regex.Replace(line, "\\s+", "\t").Split('\t'); int arrOffset = 0; try { if ((arr.Length < 4) || ((defaultZone == null) && (arr[0] != "Zone"))) throw new Exception("Неверный формат строки(1)"); if (arr[0] == "Zone") { // The first token of the string is not empty. // Therefore it must be a new zone // Create a new zone zone = new Zone(); zone.Name = arr[1]; Since = DateTime.MinValue; arrOffset = 2; } else { if (arr[0].Length != 0) throw new Exception("Неверный формат строки(2)"); // The first token of the string is empty // Therefore this is another rule of the last zone zone = defaultZone; Since = defaultZone.ZoneRules[defaultZone.ZoneRules.Count - 1].Until; arrOffset = 1; } // Create a new ZoneRule for storing these details ZoneRule zoneRule = new ZoneRule(); zone.ZoneRules.Add(zoneRule); zoneRule.ZoneName = zone.Name; zoneRule.Since = Since; zoneRule.GmtOffset = Database.ConvertToTimeSpan(arr[arrOffset]); zoneRule.RuleName = arr[arrOffset + 1]; zoneRule.Format = arr[arrOffset + 2]; arrOffset += 3; // Handle until date if (arrOffset + 1 > arr.Length) { // There are no more values in the array. // Let's set the Until date as forever zoneRule.Until = DateTime.MaxValue; } else { // There is a Until value set int year = Convert.ToInt32(arr[arrOffset++]); int month = 1; int day = 1; int hour = 0; int min = 0; int sec = 0; // Parse the month if (arrOffset + 1 < arr.Length) { month = Database.ConvertToMonth(arr[arrOffset++]); if (arrOffset + 1 < arr.Length) { if (!Int32.TryParse(arr[arrOffset++], out day)) { day = Database.ConvertToDateTime(arr[arrOffset - 1], year, month).Day; } if (arrOffset + 1 < arr.Length) { TimeSpan ts = Database.ConvertToTimeSpan(arr[arrOffset]); hour = ts.Hours; min = ts.Minutes; sec = ts.Seconds; } } } zoneRule.Until = new DateTime(year, month, day, hour, min, sec, DateTimeKind.Local); } } catch (Exception E) { throw new Exception(String.Format("Ошибка разбора зоны '{0}': {1}", line, E.Message)); } return zone; }