/// <summary> /// Construit l'ensemble des règles chargées /// </summary> /// <remarks> /// La date de début d'une zone ne correspond pas forcement à la date de fin de zone précédente. Exemple avec Pacific/Samoa ou /// on perd 1 journée le 30 décembre 2011 /// Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 /// -11:26:56 - LMT 1911 /// -11:30 - -1130 1950 /// -11:00 WS -11/-10 2011 Dec 29 24:00 /// 13:00 WS +13/+14 /// /// Certaines dates de fin peuvent coincider avec des règles de changement /// Exemple : America/Grand_Turk /// -5:00 US E%sT 2015 Nov Sun>=1 2:00 coincide avec la régle Rule US 2007 max - Nov Sun>=1 2:00 0 S /// -4:00 - AST 2018 Mar 11 3:00 /// 1/11/2015 01:00 EDT (sunday locale) => 05:00u /// 1/11/2015 02:00 AST (sunday locale) => 06:00u /// /// -4:00 - AST 2018 Mar 11 3:00 coincide avec la régle Rule US 2007 max - Mar Sun>=8 2:00 (07:00 +5) 1:00 D /// -5:00 US E%sT /// 11/03/2018 02:00 AST => 06:00u /// 11/03/2018 03:00 EDT => 07:00u /// 11/03/2018 04:00 EDT => 08:00u /// /// La date de début UTC de la zone suivante est la date de fin UTC de la zone précédente, ce n'est pas vrai pour ce qui concerne les /// dates locales. Exemple de samoa qui avance de 24 heures. /// /// Date de début : On construit la date à partir de la date utc précédente et on applique la régle courante pour obtenir la date locale /// Date de fin : On construit la date à partir de la date until en appliquant le changement DST précédent strictement inférieure /// </remarks> private static void BuildZone() { var ienum = _zones.GetEnumerator(); while (ienum.MoveNext()) { TzTimeZone temp = ienum.Current.Value; TimeSpan stdoff = TimeSpan.Zero; // Coordonnées de la zone var tz = _countryCode.SelectMany(e => e.TZone).FirstOrDefault(e => e.TZName == temp.Name); temp.Coordinates = tz.coordinates; temp.Comment = tz.comment; for (int index = 0; index < temp.ZoneRules.Count; index++) { TzTimeZoneRule zr = temp.ZoneRules[index]; // Zone avec un décalage fixe if (zr.RuleName != "-" && !_rules.ContainsKey(zr.RuleName)) { zr.FixedStandardOffset = TzUtilities.GetHMS(zr.RuleName); // Dans ce cas précis le formatage % n'est pas autorisé if (zr.Format.Contains("%")) { throw new ArgumentException("%s in ruleless zone " + temp.Name + "(" + temp.Filename + "," + temp.LineNumber + ")"); } } #region Start date if (index == 0) { zr.StartZone = TzTimeZoneRuleDate.MinValue; } else { DateTime previousUTCDate = temp.ZoneRules[index - 1].EndZone.UtcDate; TimeSpan previousStandardOffset = temp.ZoneRules[index - 1].EndZone.StandardOffset; if (zr.RuleName == "-") { zr.StartZone = new TzTimeZoneRuleDate(previousUTCDate, zr.GmtOffset, TimeSpan.Zero); } else if (!_rules.ContainsKey(zr.RuleName)) { zr.StartZone = new TzTimeZoneRuleDate(previousUTCDate, zr.GmtOffset, zr.FixedStandardOffset); } else { // Il faut rechercher si pour la date UTC on aurait une régle qui s'applique Rule lastRule = TzTimeZone.GetRuleAtPoint(_rules[zr.RuleName], previousUTCDate, zr.GmtOffset, previousStandardOffset); zr.StartZone = new TzTimeZoneRuleDate(previousUTCDate, zr.GmtOffset, lastRule?.StandardOffset ?? previousStandardOffset); } } #endregion #region End date if (zr.Until == null) { zr.EndZone = TzTimeZoneRuleDate.MaxValue; } else if (zr.RuleName == "-") { stdoff = TimeSpan.Zero; zr.EndZone = new TzTimeZoneRuleDate(TzUtilities.GetDateTime(zr.Until, zr.Until.Year, zr.GmtOffset, stdoff, DateTimeKind.Utc), zr.GmtOffset, stdoff); } else if (!_rules.ContainsKey(zr.RuleName)) { // Zone avec décalage fixe stdoff = zr.FixedStandardOffset; zr.EndZone = new TzTimeZoneRuleDate(TzUtilities.GetDateTime(zr.Until, zr.Until.Year, zr.GmtOffset, stdoff, DateTimeKind.Utc), zr.GmtOffset, stdoff); } else { Rule lastRule = TzTimeZone.GetLastStandardOffset(_rules[zr.RuleName], zr.Until, zr.StartZone, zr.GmtOffset, RuleSearchKind.LessThan); if (lastRule != null) { stdoff = lastRule.StandardOffset; } zr.EndZone = new TzTimeZoneRuleDate(TzUtilities.GetDateTime(zr.Until, zr.Until.Year, zr.GmtOffset, stdoff, DateTimeKind.Utc), zr.GmtOffset, stdoff); } #endregion } } }