예제 #1
0
        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()));
            }
        }