/// <summary>
        /// Construct an XsdDuration from a TimeSpan value that represents an xsd:duration, an xdt:dayTimeDuration, or
        /// an xdt:yearMonthDuration.
        /// </summary>
        public XsdDuration(TimeSpan timeSpan, DurationType durationType)
        {
            long  ticks = timeSpan.Ticks;
            ulong ticksPos;
            bool  isNegative;

            if (ticks < 0)
            {
                // Note that (ulong) -Int64.MinValue = Int64.MaxValue + 1, which is what we want for that special case
                isNegative = true;
                ticksPos   = (ulong)-ticks;
            }
            else
            {
                isNegative = false;
                ticksPos   = (ulong)ticks;
            }

            if (durationType == DurationType.YearMonthDuration)
            {
                int years  = (int)(ticksPos / ((ulong)TimeSpan.TicksPerDay * 365));
                int months = (int)((ticksPos % ((ulong)TimeSpan.TicksPerDay * 365)) / ((ulong)TimeSpan.TicksPerDay * 30));

                if (months == 12)
                {
                    // If remaining days >= 360 and < 365, then round off to year
                    years++;
                    months = 0;
                }

                this = new XsdDuration(isNegative, years, months, 0, 0, 0, 0, 0);
            }
            else
            {
                Debug.Assert(durationType == DurationType.Duration || durationType == DurationType.DayTimeDuration);

                // Tick count is expressed in 100 nanosecond intervals
                _nanoseconds = (uint)(ticksPos % 10000000) * 100;
                if (isNegative)
                {
                    _nanoseconds |= NegativeBit;
                }

                _years   = 0;
                _months  = 0;
                _days    = (int)(ticksPos / (ulong)TimeSpan.TicksPerDay);
                _hours   = (int)((ticksPos / (ulong)TimeSpan.TicksPerHour) % 24);
                _minutes = (int)((ticksPos / (ulong)TimeSpan.TicksPerMinute) % 60);
                _seconds = (int)((ticksPos / (ulong)TimeSpan.TicksPerSecond) % 60);
            }
        }
        ///<include file='doc\XmlConvert.uex' path='docs/doc[@for="XmlConvert.ToTimeSpan"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static TimeSpan ToTimeSpan(string s)
        {
            XsdDuration duration;
            TimeSpan    timeSpan;

            try
            {
                duration = new XsdDuration(s);
            }
            catch (Exception)
            {
                // Remap exception for v1 compatibility
                throw new FormatException(SR.Format(SR.XmlConvert_BadFormat, s, "TimeSpan"));
            }

            timeSpan = duration.ToTimeSpan();

            return(timeSpan);
        }
        internal static Exception TryParse(string s, DurationType durationType, out XsdDuration result)
        {
            string errorCode;
            int    length;
            int    value, pos, numDigits;
            Parts  parts = Parts.HasNone;

            result = new XsdDuration();

            s      = s.Trim();
            length = s.Length;

            pos       = 0;
            numDigits = 0;

            if (pos >= length)
            {
                goto InvalidFormat;
            }

            if (s[pos] == '-')
            {
                pos++;
                result._nanoseconds = NegativeBit;
            }
            else
            {
                result._nanoseconds = 0;
            }

            if (pos >= length)
            {
                goto InvalidFormat;
            }

            if (s[pos++] != 'P')
            {
                goto InvalidFormat;
            }

            errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
            if (errorCode != null)
            {
                goto Error;
            }

            if (pos >= length)
            {
                goto InvalidFormat;
            }

            if (s[pos] == 'Y')
            {
                if (numDigits == 0)
                {
                    goto InvalidFormat;
                }

                parts        |= Parts.HasYears;
                result._years = value;
                if (++pos == length)
                {
                    goto Done;
                }

                errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                if (errorCode != null)
                {
                    goto Error;
                }

                if (pos >= length)
                {
                    goto InvalidFormat;
                }
            }

            if (s[pos] == 'M')
            {
                if (numDigits == 0)
                {
                    goto InvalidFormat;
                }

                parts         |= Parts.HasMonths;
                result._months = value;
                if (++pos == length)
                {
                    goto Done;
                }

                errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                if (errorCode != null)
                {
                    goto Error;
                }

                if (pos >= length)
                {
                    goto InvalidFormat;
                }
            }

            if (s[pos] == 'D')
            {
                if (numDigits == 0)
                {
                    goto InvalidFormat;
                }

                parts       |= Parts.HasDays;
                result._days = value;
                if (++pos == length)
                {
                    goto Done;
                }

                errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                if (errorCode != null)
                {
                    goto Error;
                }

                if (pos >= length)
                {
                    goto InvalidFormat;
                }
            }

            if (s[pos] == 'T')
            {
                if (numDigits != 0)
                {
                    goto InvalidFormat;
                }

                pos++;
                errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                if (errorCode != null)
                {
                    goto Error;
                }

                if (pos >= length)
                {
                    goto InvalidFormat;
                }

                if (s[pos] == 'H')
                {
                    if (numDigits == 0)
                    {
                        goto InvalidFormat;
                    }

                    parts        |= Parts.HasHours;
                    result._hours = value;
                    if (++pos == length)
                    {
                        goto Done;
                    }

                    errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                    if (errorCode != null)
                    {
                        goto Error;
                    }

                    if (pos >= length)
                    {
                        goto InvalidFormat;
                    }
                }

                if (s[pos] == 'M')
                {
                    if (numDigits == 0)
                    {
                        goto InvalidFormat;
                    }

                    parts          |= Parts.HasMinutes;
                    result._minutes = value;
                    if (++pos == length)
                    {
                        goto Done;
                    }

                    errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
                    if (errorCode != null)
                    {
                        goto Error;
                    }

                    if (pos >= length)
                    {
                        goto InvalidFormat;
                    }
                }

                if (s[pos] == '.')
                {
                    pos++;

                    parts          |= Parts.HasSeconds;
                    result._seconds = value;

                    errorCode = TryParseDigits(s, ref pos, true, out value, out numDigits);
                    if (errorCode != null)
                    {
                        goto Error;
                    }

                    if (numDigits == 0)
                    { //If there are no digits after the decimal point, assume 0
                        value = 0;
                    }
                    // Normalize to nanosecond intervals
                    for (; numDigits > 9; numDigits--)
                    {
                        value /= 10;
                    }

                    for (; numDigits < 9; numDigits++)
                    {
                        value *= 10;
                    }

                    result._nanoseconds |= (uint)value;

                    if (pos >= length)
                    {
                        goto InvalidFormat;
                    }

                    if (s[pos] != 'S')
                    {
                        goto InvalidFormat;
                    }
                    if (++pos == length)
                    {
                        goto Done;
                    }
                }
                else if (s[pos] == 'S')
                {
                    if (numDigits == 0)
                    {
                        goto InvalidFormat;
                    }

                    parts          |= Parts.HasSeconds;
                    result._seconds = value;
                    if (++pos == length)
                    {
                        goto Done;
                    }
                }
            }

            // Duration cannot end with digits
            if (numDigits != 0)
            {
                goto InvalidFormat;
            }

            // No further characters are allowed
            if (pos != length)
            {
                goto InvalidFormat;
            }

Done:
            // At least one part must be defined
            if (parts == Parts.HasNone)
            {
                goto InvalidFormat;
            }

            if (durationType == DurationType.DayTimeDuration)
            {
                if ((parts & (Parts.HasYears | Parts.HasMonths)) != 0)
                {
                    goto InvalidFormat;
                }
            }
            else if (durationType == DurationType.YearMonthDuration)
            {
                if ((parts & ~(XsdDuration.Parts.HasYears | XsdDuration.Parts.HasMonths)) != 0)
                {
                    goto InvalidFormat;
                }
            }
            return(null);

InvalidFormat:
            return(new FormatException(SR.Format(SR.XmlConvert_BadFormat, s, durationType)));

Error:
            return(new OverflowException(SR.Format(SR.XmlConvert_Overflow, s, durationType)));
        }