/// <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); } }
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(string.Format(ResXml.XmlConvert_BadFormat, s, durationType))); Error: return(new OverflowException(string.Format(ResXml.XmlConvert_Overflow, s, durationType))); }
internal static Exception TryParse(string s, out XsdDuration result) { return(TryParse(s, DurationType.Duration, out result)); }