private static TimeZoneInfo ParseTZBuffer(string id, byte [] buffer, int length) { //Reading the header. 4 bytes for magic, 16 are reserved int ttisgmtcnt = ReadBigEndianInt32(buffer, 20); int ttisstdcnt = ReadBigEndianInt32(buffer, 24); int leapcnt = ReadBigEndianInt32(buffer, 28); int timecnt = ReadBigEndianInt32(buffer, 32); int typecnt = ReadBigEndianInt32(buffer, 36); int charcnt = ReadBigEndianInt32(buffer, 40); if (length < 44 + timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisgmtcnt) { throw new InvalidTimeZoneException(); } Dictionary <int, string> abbreviations = ParseAbbreviations(buffer, 44 + 4 * timecnt + timecnt + 6 * typecnt, charcnt); Dictionary <int, TimeType> time_types = ParseTimesTypes(buffer, 44 + 4 * timecnt + timecnt, typecnt, abbreviations); List <KeyValuePair <DateTime, TimeType> > transitions = ParseTransitions(buffer, 44, timecnt, time_types); if (time_types.Count == 0) { throw new InvalidTimeZoneException(); } if (time_types.Count == 1 && ((TimeType)time_types[0]).IsDst) { throw new InvalidTimeZoneException(); } TimeSpan baseUtcOffset = new TimeSpan(0); TimeSpan dstDelta = new TimeSpan(0); string standardDisplayName = null; string daylightDisplayName = null; bool dst_observed = false; DateTime dst_start = DateTime.MinValue; List <AdjustmentRule> adjustmentRules = new List <AdjustmentRule> (); for (int i = 0; i < transitions.Count; i++) { var pair = transitions [i]; DateTime ttime = pair.Key; TimeType ttype = pair.Value; if (!ttype.IsDst) { if (standardDisplayName != ttype.Name || baseUtcOffset.TotalSeconds != ttype.Offset) { standardDisplayName = ttype.Name; daylightDisplayName = null; baseUtcOffset = new TimeSpan(0, 0, ttype.Offset); adjustmentRules = new List <AdjustmentRule> (); dst_observed = false; } if (dst_observed) { //FIXME: check additional fields for this: //most of the transitions are expressed in GMT dst_start += baseUtcOffset; DateTime dst_end = ttime + baseUtcOffset + dstDelta; //some weird timezone (America/Phoenix) have end dates on Jan 1st if (dst_end.Date == new DateTime(dst_end.Year, 1, 1) && dst_end.Year > dst_start.Year) { dst_end -= new TimeSpan(24, 0, 0); } DateTime dateStart, dateEnd; if (dst_start.Month < 7) { dateStart = new DateTime(dst_start.Year, 1, 1); } else { dateStart = new DateTime(dst_start.Year, 7, 1); } if (dst_end.Month >= 7) { dateEnd = new DateTime(dst_end.Year, 12, 31); } else { dateEnd = new DateTime(dst_end.Year, 6, 30); } TransitionTime transition_start = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1) + dst_start.TimeOfDay, dst_start.Month, dst_start.Day); TransitionTime transition_end = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1) + dst_end.TimeOfDay, dst_end.Month, dst_end.Day); if (transition_start != transition_end) //y, that happened in Argentina in 1943-1946 { adjustmentRules.Add(AdjustmentRule.CreateAdjustmentRule(dateStart, dateEnd, dstDelta, transition_start, transition_end)); } } dst_observed = false; } else { if (daylightDisplayName != ttype.Name || dstDelta.TotalSeconds != ttype.Offset - baseUtcOffset.TotalSeconds) { daylightDisplayName = ttype.Name; dstDelta = new TimeSpan(0, 0, ttype.Offset) - baseUtcOffset; } dst_start = ttime; dst_observed = true; } } if (adjustmentRules.Count == 0) { TimeType t = (TimeType)time_types [0]; if (standardDisplayName == null) { standardDisplayName = t.Name; baseUtcOffset = new TimeSpan(0, 0, t.Offset); } return(CreateCustomTimeZone(id, baseUtcOffset, id, standardDisplayName)); } else { return(CreateCustomTimeZone(id, baseUtcOffset, id, standardDisplayName, daylightDisplayName, ValidateRules(adjustmentRules).ToArray())); } }