/// <summary> /// Obtient le standard offset applicable à une règle /// </summary> /// <param name="year"></param> /// <param name="rules"></param> /// <param name="rule"></param> /// <param name="zoneDate"></param> /// <param name="gmtOffset"></param> /// <returns></returns> /// <remarks>Cette fonction compare des règles définies, comme un changement d'heure ne se /// produit pas en même temps qu'un autre on peut appliquer le stdoff entre règles sans /// se soucier de point recouvrant. /// </remarks> private static TimeSpan GetLastSaveOffset(int year, List<Rule> rules, Rule rule, TzTimeZoneRuleDate zoneDate, TimeSpan gmtOffset) { int bestyear = -1; TimeSpan range = TimeSpan.MaxValue; TimeSpan stdoff = zoneDate.StandardOffset; for (int index = rules.Count - 1; index >= 0; index--) { if (rules[index] == rule) continue; if (rules[index].LowerYear > year || rules[index].HighYear < bestyear) { continue; } int yref = (rules[index].HighYear > year) ? year : rules[index].HighYear; if (yref == year && rules[index].AtKind == rule.AtKind && (rules[index].Month > rule.Month || (rules[index].Month == rule.Month && rules[index].Day.DayWork == DayWorkKind.Dom && rule.Day.DayWork == DayWorkKind.Dom && rules[index].Day.DayOfMonth > rule.Day.DayOfMonth))) { if (yref > rules[index].LowerYear) yref--; else continue; } for (; yref >= rules[index].LowerYear; yref--) { if (!TzUtilities.IsYearType(yref, rules[index].YearType)) continue; DateTime precedent; DateTime current; // On compare la date avec la date limite de zone if (rules[index].AtKind == TimeKind.LocalWallTime) { precedent = TzUtilities.GetDateTime(rules[index], yref, gmtOffset, TimeSpan.Zero, DateTimeKind.Local); if (zoneDate.ToLocalTime() > precedent) break; // On exprime la date courante de la règle à vérifier en local current = TzUtilities.GetDateTime(rule, year, gmtOffset, rules[index].StandardOffset, DateTimeKind.Local); } else { precedent = TzUtilities.GetDateTime(rules[index], yref, gmtOffset, TimeSpan.Zero, DateTimeKind.Utc); if (zoneDate.UtcDate > precedent) break; // On exprime la date courante de la règle à vérifier en utc current = TzUtilities.GetDateTime(rule, year, gmtOffset, rules[index].StandardOffset, DateTimeKind.Utc); } if (precedent > current) { continue; } else { TimeSpan diff = current - precedent; if (range > diff) { stdoff = rules[index].StandardOffset; range = diff; bestyear = precedent.Year; } break; } } } return stdoff; }
/// <summary> /// Obtient une règle en fonction de sa description /// </summary> /// <param name="ruleDescription"></param> /// <returns> /// # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S /// </returns> public static Rule GetRule(List<string> ruleDescription) { Rule r = new Rule(); Debug.Assert(ruleDescription.Count == 10); Debug.Assert(ruleDescription[0] == "Rule"); r.Name = ruleDescription[1]; r.StandardOffset = GetHMS(ruleDescription[8]); r.Letter = ruleDescription[9]; string loyearp = ruleDescription[2]; string hiyearp = ruleDescription[3]; string typep = ruleDescription[4]; // Year work // Min Year (FROM) IEnumerable<string> by = BeginYears.Where(e => itsabbr(loyearp, e)); if (by.Count() == 0) { r.LowerYear = Int32.Parse(loyearp); } else if (by.Count() == 1) { if (by.ElementAt(0) == BeginYears[0]) r.LowerYear = DateTime.MinValue.Year; else r.LowerYear = DateTime.MaxValue.Year; } else { throw new ArgumentException("Multiple inexact match", loyearp); } // Max Year (TO) by = EndYears.Where(e => itsabbr(hiyearp, e)); if (by.Count() == 0) { r.HighYear = Int32.Parse(hiyearp); } else if (by.Count() == 1) { if (by.ElementAt(0) == EndYears[0]) r.HighYear = DateTime.MinValue.Year; else if (by.ElementAt(0) == EndYears[1]) r.HighYear = DateTime.MaxValue.Year; else r.HighYear = r.LowerYear; } else { throw new ArgumentException("Multiple inexact match", hiyearp); } if (r.LowerYear > r.HighYear) throw new ArgumentException("Starting year greater than ending year"); // Type (TYPE) switch (typep) { case "": case "-": r.YearType = YearType.none; break; case "even": r.YearType = YearType.even; break; case "odd": r.YearType = YearType.odd; break; case "uspres": r.YearType = YearType.uspres; break; case "nonpres": r.YearType = YearType.nonpres; break; case "nonuspres": r.YearType = YearType.nonuspres; break; default: throw new ArgumentException("Unknown type " + typep); } SetRuleSub(r, ruleDescription[5], ruleDescription[6], ruleDescription[7]); return r; }