2007-11-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System / TimeSpan.cs
index 4061503c34bfd6611b19211f8572a3ee546228dc..9ae9da02a9444e0b7cb81e033bc606f478aafafa 100644 (file)
 //
 // System.TimeSpan.cs
 //
-// author:
+// Authors:
 //   Duco Fijma (duco@lorentz.xs4all.nl)
+//   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+//   Sebastien Pouliot  <sebastien@ximian.com>
+//
+// (C) 2001 Duco Fijma
+// (C) 2004 Andreas Nahr
+// Copyright (C) 2004 Novell (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-//   (C) 2001 Duco Fijma
-
-namespace System {
-       
-       public struct TimeSpan :  IComparable  {
-               private long ticks;
-
-               // Ctors
-
-               public TimeSpan (long value) { ticks = value; }
-               public TimeSpan (int hours, int minutes, int seconds) 
-                       : this(0, hours, minutes, seconds, 0) {}
-               public TimeSpan (int days, int hours, int minutes, int seconds) 
-                       : this(days, hours, minutes, seconds, 0) {}
-               public TimeSpan (int days, int hours, int minutes, int seconds, int milliseconds)
-               {
-                       ticks = TicksPerDay * days + 
-                               TicksPerHour * hours +
-                               TicksPerMinute * minutes +
-                               TicksPerSecond * seconds +
-                               TicksPerMillisecond * milliseconds;
-               }
-               
-               // Fields
 
+using System.Text;
+
+namespace System
+{
+       [Serializable]
+#if NET_2_0
+       [System.Runtime.InteropServices.ComVisible (true)]
+#endif
+       public struct TimeSpan : IComparable
+#if NET_2_0
+               , IComparable<TimeSpan>, IEquatable <TimeSpan>
+#endif
+       {
                public static readonly TimeSpan MaxValue = new TimeSpan (long.MaxValue);
                public static readonly TimeSpan MinValue = new TimeSpan (long.MinValue);
+               public static readonly TimeSpan Zero = new TimeSpan (0L);
+
                public const long TicksPerDay = 864000000000L;
                public const long TicksPerHour = 36000000000L;
                public const long TicksPerMillisecond = 10000L;
                public const long TicksPerMinute = 600000000L;
                public const long TicksPerSecond = 10000000L;
-               public static readonly TimeSpan Zero = new TimeSpan (0L);
 
-               // Properties
+               private long _ticks;
 
-               public int Days
+               public TimeSpan (long value)
                {
-                       get {
-                               return (int) TotalDays;
-                       }
+                       _ticks = value;
+               }
+
+               public TimeSpan (int hours, int minutes, int seconds)
+               {
+                       _ticks = CalculateTicks (0, hours, minutes, seconds, 0);
+               }
+
+               public TimeSpan (int days, int hours, int minutes, int seconds)
+               {
+                       _ticks = CalculateTicks (days, hours, minutes, seconds, 0);
                }
 
-               public int Hours
+               public TimeSpan (int days, int hours, int minutes, int seconds, int milliseconds)
                {
+                       _ticks = CalculateTicks (days, hours, minutes, seconds, milliseconds);
+               }
+
+               internal static long CalculateTicks (int days, int hours, int minutes, int seconds, int milliseconds)
+               {
+                       // there's no overflow checks for hours, minutes, ...
+                       // so big hours/minutes values can overflow at some point and change expected values
+                       int hrssec = (hours * 3600); // break point at (Int32.MaxValue - 596523)
+                       int minsec = (minutes * 60);
+                       long t = ((long)(hrssec + minsec + seconds) * 1000L + (long)milliseconds);
+                       t *= 10000;
+
+                       bool overflow = false;
+                       // days is problematic because it can overflow but that overflow can be 
+                       // "legal" (i.e. temporary) (e.g. if other parameters are negative) or 
+                       // illegal (e.g. sign change).
+                       if (days > 0) {
+                               long td = TicksPerDay * days;
+                               if (t < 0) {
+                                       long ticks = t;
+                                       t += td;
+                                       // positive days -> total ticks should be lower
+                                       overflow = (ticks > t);
+                               }
+                               else {
+                                       t += td;
+                                       // positive + positive != negative result
+                                       overflow = (t < 0);
+                               }
+                       }
+                       else if (days < 0) {
+                               long td = TicksPerDay * days;
+                               if (t <= 0) {
+                                       t += td;
+                                       // negative + negative != positive result
+                                       overflow = (t > 0);
+                               }
+                               else {
+                                       long ticks = t;
+                                       t += td;
+                                       // negative days -> total ticks should be lower
+                                       overflow = (t > ticks);
+                               }
+                       }
+
+                       if (overflow)
+                               throw new ArgumentOutOfRangeException (Locale.GetText ("The timespan is too big or too small."));
+
+                       return t;
+               }
+
+               public int Days {
                        get {
-                               return (int) (ticks % TicksPerDay / TicksPerHour);
+                               return (int) (_ticks / TicksPerDay);
                        }
                }
 
-               public int Milliseconds
-               {
-                       get
-                       {
-                               return (int) (ticks % TicksPerSecond / TicksPerMillisecond);
+               public int Hours {
+                       get {
+                               return (int) (_ticks % TicksPerDay / TicksPerHour);
                        }
                }
 
-               public int Minutes
-               {
-                       get
-                       {
-                               return (int) (ticks % TicksPerHour / TicksPerMinute);
+               public int Milliseconds {
+                       get {
+                               return (int) (_ticks % TicksPerSecond / TicksPerMillisecond);
                        }
                }
 
-               public int Seconds
-               {
-                       get
-                       {
-                               return (int) (ticks % TicksPerMinute / TicksPerSecond);
+               public int Minutes {
+                       get {
+                               return (int) (_ticks % TicksPerHour / TicksPerMinute);
                        }
                }
 
-               public long Ticks
-               { 
-                       get
-                       {
-                               return ticks;
+               public int Seconds {
+                       get {
+                               return (int) (_ticks % TicksPerMinute / TicksPerSecond);
                        }
                }
 
-               public double TotalDays
-               {
-                       get
-                       {
-                               return (double) ticks / TicksPerDay;
+               public long Ticks {
+                       get {
+                               return _ticks;
                        }
                }
 
-               public double TotalHours
-               {
-                       get
-                       {
-                               return (double) ticks / TicksPerHour;
+               public double TotalDays {
+                       get {
+                               return (double) _ticks / TicksPerDay;
                        }
                }
 
-               public double TotalMilliseconds
-               {
-                       get
-                       {
-                               return (double) ticks  / TicksPerMillisecond;
+               public double TotalHours {
+                       get {
+                               return (double) _ticks / TicksPerHour;
                        }
                }
 
-               public double TotalMinutes
-               {
+               public double TotalMilliseconds {
                        get {
-                               return (double) ticks / TicksPerMinute;
+                               return (double) _ticks  / TicksPerMillisecond;
                        }
                }
 
-               public double TotalSeconds
-               {
+               public double TotalMinutes {
                        get {
-                               return (double) ticks / TicksPerSecond;
+                               return (double) _ticks / TicksPerMinute;
                        }
                }
 
-               // Methods
+               public double TotalSeconds {
+                       get {
+                               return (double) _ticks / TicksPerSecond;
+                       }
+               }
 
                public TimeSpan Add (TimeSpan ts)
                {
-                       checked {
-                               return new TimeSpan (ticks+ts.Ticks);
+                       try {
+                               checked {
+                                       return new TimeSpan (_ticks + ts.Ticks);
+                               }
+                       }
+                       catch (OverflowException) {
+                               throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
                        }
                }
 
                public static int Compare (TimeSpan t1, TimeSpan t2)
                {
-                       if (t1.ticks < t2.ticks) {
+                       if (t1._ticks < t2._ticks)
                                return -1;
-                       }
-                       else if (t1.ticks > t2.ticks) {
+                       if (t1._ticks > t2._ticks)
                                return 1;
-                       }
-                       else {
-                               return 0;
-                       }
+                       return 0;
                }
 
                public int CompareTo (object value)
                {
-                       
-                       if (value == null ) {
+                       if (value == null)
                                return 1;
-                       }
 
                        if (!(value is TimeSpan)) {
-                               throw new ArgumentException("Argument of System.TimeSpan.CompareTo should be a TimeSpan");
+                               throw new ArgumentException (Locale.GetText ("Argument has to be a TimeSpan."), "value");
                        }
-               
-                       return Compare(this, (TimeSpan) value);
+
+                       return Compare (this, (TimeSpan) value);
+               }
+
+#if NET_2_0
+               public int CompareTo (TimeSpan value)
+               {
+                       return Compare (this, value);
+               }
+
+               public bool Equals (TimeSpan value)
+               {
+                       return value._ticks == _ticks;
                }
+#endif
 
-               // Overflow issue for Duration is like for Negate.
                public TimeSpan Duration ()
                {
-                       checked {
-                               return new TimeSpan (Math.Abs (ticks));
+                       try {
+                               checked {
+                                       return new TimeSpan (Math.Abs (_ticks));
+                               }
+                       }
+                       catch (OverflowException) {
+                               throw new OverflowException (Locale.GetText (
+                                       "This TimeSpan value is MinValue so you cannot get the duration."));
                        }
                }
 
-               // TODO: Consider implementing this version
-               // in terms of Equals(TimeSPan, TimeSpan)
                public override bool Equals (object value)
                {
-                       if (value == null || !(value is TimeSpan)) {
+                       if (!(value is TimeSpan))
                                return false;
-                       }
-                       return ticks == ((TimeSpan) (value)).ticks;
+
+                       return _ticks == ((TimeSpan) value)._ticks;
                }
 
-               public static new bool Equals(TimeSpan t1, TimeSpan t2)
+               public static bool Equals (TimeSpan t1, TimeSpan t2)
                {
-                       return t1.Equals (t2);
+                       return t1._ticks == t2._ticks;
                }
 
-               // Implementing FromDays -> FromHours -> FromMinutes -> FromSeconds ->
-               // FromMilliseconds as done here is probably not the most efficient
-               // way. 
-
                public static TimeSpan FromDays (double value)
                {
-                       if (Double.IsNaN(value) || Double.IsNegativeInfinity(value)) {
-                               return MinValue;
-                       }
-
-                       if (Double.IsPositiveInfinity(value)) {
-                               return MaxValue;
-                       }
-
-                       return new TimeSpan((int) value,0,0,0,0) + FromHours ((value - ((int) value)) * 24);
+                       return From (value, TicksPerDay);
                }
 
                public static TimeSpan FromHours (double value)
                {
-                       if (Double.IsNaN(value) || Double.IsNegativeInfinity(value)) {
-                               return MinValue;
-                       }
-
-                       if (Double.IsPositiveInfinity(value)) {
-                               return MaxValue;
-                       }
-
-                       return new TimeSpan ((int) value,0,0) + FromMinutes ((value - ((int) value)) * 60);
+                       return From (value, TicksPerHour);
                }
 
-               public static TimeSpan FromMinutes(double value)
+               public static TimeSpan FromMinutes (double value)
                {
-                       if (Double.IsNaN(value) || Double.IsNegativeInfinity(value)) {
-                               return MinValue;
-                       }
-
-                       if (Double.IsPositiveInfinity(value)) {
-                               return MaxValue;
-                       }
+                       return From (value, TicksPerMinute);
+               }
 
-                       return new TimeSpan (0,(int) value,0) + FromSeconds((value - ((int) value)) * 60);
+               public static TimeSpan FromSeconds (double value)
+               {
+                       return From (value, TicksPerSecond);
                }
 
-               public static TimeSpan FromSeconds(double value)
+               public static TimeSpan FromMilliseconds (double value)
                {
-                       if (Double.IsNaN(value) || Double.IsNegativeInfinity(value)) {
-                               return MinValue;
-                       }
+                       return From (value, TicksPerMillisecond);
+               }
 
-                       if (Double.IsPositiveInfinity(value)) {
-                               return MaxValue;
-                       }
+               private static TimeSpan From (double value, long tickMultiplicator) 
+               {
+                       if (Double.IsNaN (value))
+                               throw new ArgumentException (Locale.GetText ("Value cannot be NaN."), "value");
+                       if (Double.IsNegativeInfinity (value) || Double.IsPositiveInfinity (value) ||
+                               (value < MinValue.Ticks) || (value > MaxValue.Ticks))
+                               throw new OverflowException (Locale.GetText ("Outside range [MinValue,MaxValue]"));
 
-                       return new TimeSpan (0,0,0,(int) value,((int) ((value - ((int) value)) * 1000)));
+                       try {
+                               value = (value * (tickMultiplicator / TicksPerMillisecond));
 
+                               checked {
+                                       long val = (long) Math.Round(value);
+                                       return new TimeSpan (val * TicksPerMillisecond);
+                               }
+                       }
+                       catch (OverflowException) {
+                               throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
+                       }
                }
 
                public static TimeSpan FromTicks (long value)
@@ -245,110 +311,307 @@ namespace System {
                        return new TimeSpan (value);
                }
 
-               public override int GetHashCode()
+               public override int GetHashCode ()
                {
-                       return ticks.GetHashCode();
+                       return _ticks.GetHashCode ();
                }
 
-               // TODO: It makes sense that Negate can throw an overflow
-               // exception (if negating MinValue). Is this specified
-               // somewhere?
-               public TimeSpan Negate()
+               public TimeSpan Negate ()
                {
-                       checked {
-                               return new TimeSpan(- ticks);
-                       }
+                       if (_ticks == MinValue._ticks)
+                               throw new OverflowException (Locale.GetText (
+                                       "This TimeSpan value is MinValue and cannot be negated."));
+                       return new TimeSpan (-_ticks);
                }
 
-               // TODO: implement
-               public static TimeSpan Parse(string s) 
+               public static TimeSpan Parse (string s)
                {
-                       return Zero;
+                       if (s == null) {
+                               throw new ArgumentNullException ("s");
+                       }
+
+                       Parser p = new Parser (s);
+                       return p.Execute ();
                }
 
-               public TimeSpan Subtract(TimeSpan ts)
+#if NET_2_0
+               public static bool TryParse (string s, out TimeSpan result)
                {
-                       checked {
-                               return new TimeSpan(ticks - ts.Ticks);
+                       try {
+                               result = Parse (s);
+                               return true;
+                       } catch {
+                               result = TimeSpan.Zero;
+                               return false;
                        }
                }
+#endif
 
-               public override string ToString()
+               public TimeSpan Subtract (TimeSpan ts)
                {
-                       string res = "";        
-
-                       if (ticks < 0) {
-                               res += "-";
+                       try {
+                               checked {
+                                       return new TimeSpan (_ticks - ts.Ticks);
+                               }
+                       }
+                       catch (OverflowException) {
+                               throw new OverflowException (Locale.GetText ("Resulting timespan is too big."));
                        }
+               }
+
+               public override string ToString ()
+               {
+                       StringBuilder sb = new StringBuilder (14);
+                       
+                       if (_ticks < 0)
+                               sb.Append ('-');
 
                        // We need to take absolute values of all components.
                        // Can't handle negative timespans by negating the TimeSpan
                        // as a whole. This would lead to an overflow for the 
                        // degenerate case "TimeSpan.MinValue.ToString()".
-
                        if (Days != 0) {
-                               res += Math.Abs(Days) + "." ;
+                               sb.Append (Math.Abs (Days));
+                               sb.Append ('.');
                        }
 
-                       res += string.Format("{0:00}:{1:00}:{2:00}", Math.Abs(Hours), Math.Abs(Minutes), Math.Abs(Seconds));
+                       System.Globalization.NumberFormatInfo nfi = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
+                       sb.Append (NumberFormatter.FormatDecimal (new NumberFormatter.NumberStore ((int)Math.Abs (Hours)), 2, nfi));
+                       sb.Append (':');
+                       sb.Append (NumberFormatter.FormatDecimal (new NumberFormatter.NumberStore ((int)Math.Abs (Minutes)), 2, nfi));
+                       sb.Append (':');
+                       sb.Append (NumberFormatter.FormatDecimal (new NumberFormatter.NumberStore ((int)Math.Abs (Seconds)), 2, nfi));
 
-                       int fractional = (int) Math.Abs(ticks % TicksPerSecond);
+                       int fractional = (int) Math.Abs (_ticks % TicksPerSecond);
                        if (fractional != 0) {
-                               res += string.Format(".{0:0000000}", fractional);
+                               sb.Append ('.');
+                               sb.Append (NumberFormatter.FormatDecimal (new NumberFormatter.NumberStore (fractional), 7, nfi));
                        }
-                       return res;
+
+                       return sb.ToString ();
                }
 
-               public static TimeSpan operator +(TimeSpan t1, TimeSpan t2)
+               public static TimeSpan operator + (TimeSpan t1, TimeSpan t2)
                {
-                       return t1.Add(t2);
+                       return t1.Add (t2);
                }
 
-               public static bool operator ==(TimeSpan t1, TimeSpan t2)
+               public static bool operator == (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) == 0;
+                       return t1._ticks == t2._ticks;
                }
 
-               public static bool operator >(TimeSpan t1, TimeSpan t2)
+               public static bool operator > (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) == 1;
+                       return t1._ticks > t2._ticks;
                }
 
-               public static bool operator >=(TimeSpan t1, TimeSpan t2)
+               public static bool operator >= (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) != -1;
+                       return t1._ticks >= t2._ticks;
                }
 
-               public static bool operator !=(TimeSpan t1, TimeSpan t2)
+               public static bool operator != (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) != 0;
+                       return t1._ticks != t2._ticks;
                }
 
-               public static bool operator <(TimeSpan t1, TimeSpan t2)
+               public static bool operator < (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) == -1;
+                       return t1._ticks < t2._ticks;
                }
 
-               public static bool operator <=(TimeSpan t1, TimeSpan t2)
+               public static bool operator <= (TimeSpan t1, TimeSpan t2)
                {
-                       return Compare(t1, t2) != 1;
+                       return t1._ticks <= t2._ticks;
                }
 
-               public static TimeSpan operator -(TimeSpan t1, TimeSpan t2)
+               public static TimeSpan operator - (TimeSpan t1, TimeSpan t2)
                {
-                       return t1.Subtract(t2);
+                       return t1.Subtract (t2);
                }
 
-               public static TimeSpan operator -(TimeSpan t)
+               public static TimeSpan operator - (TimeSpan t)
                {
-                       return t.Negate();
+                       return t.Negate ();
                }
 
-               public static TimeSpan operator +(TimeSpan t)
+               public static TimeSpan operator + (TimeSpan t)
                {
                        return t;
                }
+
+               // Class Parser implements parser for TimeSpan.Parse
+               private class Parser
+               {
+                       private string _src;
+                       private int _cur = 0;
+                       private int _length;
+                       private bool formatError;
+
+                       public Parser (string src)
+                       {
+                               _src = src;
+                               _length = _src.Length;
+                       }
+       
+                       public bool AtEnd {
+                               get {
+                                       return _cur >= _length;
+                               }
+                       }
+
+                       // All "Parse" functions throw a FormatException on syntax error.
+                       // Their return value is semantic value of the item parsed.
+
+                       // Range checking is spread over three different places:
+                       // 1) When parsing "int" values, an exception is thrown immediately
+                       //    when the value parsed exceeds the maximum value for an int.
+                       // 2) An explicit check is built in that checks for hours > 23 and
+                       //    for minutes and seconds > 59.
+                       // 3) Throwing an exceptions for a final TimeSpan value > MaxValue
+                       //    or < MinValue is left to the TimeSpan constructor called.
+
+                       // Parse zero or more whitespace chars.
+                       private void ParseWhiteSpace ()
+                       {
+                               while (!AtEnd && Char.IsWhiteSpace (_src, _cur)) {
+                                       _cur++;
+                               }
+                       }
+
+                       // Parse optional sign character.
+                       private bool ParseSign ()
+                       {
+                               bool res = false;
+
+                               if (!AtEnd && _src[_cur] == '-') {
+                                       res = true;
+                                       _cur++;
+                               }
+
+                               return res;
+                       }
+
+                       // Parse simple int value
+                       private int ParseInt (bool optional)
+                       {
+                               if (optional && AtEnd)
+                                       return 0;
+
+                               int res = 0;
+                               int count = 0;
+
+                               while (!AtEnd && Char.IsDigit (_src, _cur)) {
+                                       checked {
+                                               res = res * 10 + _src[_cur] - '0';
+                                       }
+                                       _cur++;
+                                       count++;
+                               }
+
+                               if (count == 0)
+                                       formatError = true;
+
+                               return res;
+                       }
+
+                       // Parse optional dot
+                       private bool ParseOptDot ()
+                       {
+                               if (AtEnd)
+                                       return false;
+
+                               if (_src[_cur] == '.') {
+                                       _cur++;
+                                       return true;
+                               }
+                               return false;
+                       }       
+
+                       // Parse optional (LAMESPEC) colon
+                       private void ParseOptColon ()
+                       {
+                               if (!AtEnd) {
+                                       if (_src[_cur] == ':')
+                                               _cur++;
+                                       else 
+                                               formatError = true;
+                               }
+                       }
+
+                       // Parse [1..7] digits, representing fractional seconds (ticks)
+                       private long ParseTicks ()
+                       {
+                               long mag = 1000000;
+                               long res = 0;
+                               bool digitseen = false;
+                               
+                               while (mag > 0 && !AtEnd && Char.IsDigit (_src, _cur)) {
+                                       res = res + (_src[_cur] - '0') * mag;
+                                       _cur++;
+                                       mag = mag / 10;
+                                       digitseen = true;
+                               }
+
+                               if (!digitseen)
+                                       formatError = true;
+
+                               return res;
+                       }
+
+                       public TimeSpan Execute ()
+                       {
+                               bool sign;
+                               int days;
+                               int hours = 0;
+                               int minutes;
+                               int seconds;
+                               long ticks;
+
+                               // documented as...
+                               // Parse [ws][-][dd.]hh:mm:ss[.ff][ws]
+                               // ... but not entirely true as an lonely 
+                               // integer will be parsed as a number of days
+                               ParseWhiteSpace ();
+                               sign = ParseSign ();
+                               days = ParseInt (false);
+                               if (ParseOptDot ()) {
+                                       hours = ParseInt (true);
+                               }
+                               else if (!AtEnd) {
+                                       hours = days;
+                                       days = 0;
+                               }
+                               ParseOptColon();
+                               minutes = ParseInt (true);
+                               ParseOptColon ();
+                               seconds = ParseInt (true);
+                               if ( ParseOptDot () ) {
+                                       ticks = ParseTicks ();
+                               }
+                               else {
+                                       ticks = 0;
+                               }
+                               ParseWhiteSpace ();
+       
+                               if (!AtEnd)
+                                       formatError = true;
+
+                               // Overflow has presceance over FormatException
+                               if (hours > 23 || minutes > 59 || seconds > 59) {
+                                       throw new OverflowException (
+                                               Locale.GetText ("Invalid time data."));
+                               }
+                               else if (formatError) {
+                                       throw new FormatException (
+                                               Locale.GetText ("Invalid format for TimeSpan.Parse."));
+                               }
+
+                               long t = TimeSpan.CalculateTicks (days, hours, minutes, seconds, 0);
+                               t = checked ((sign) ? (-t - ticks) : (t + ticks));
+                               return new TimeSpan (t);
+                       }
+               }
        }
 }
-