5 // Duco Fijma (duco@lorentz.xs4all.nl)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
9 // (C) 2004 Andreas Nahr
17 public struct TimeSpan : IComparable
19 public static readonly TimeSpan MaxValue = new TimeSpan (long.MaxValue);
20 public static readonly TimeSpan MinValue = new TimeSpan (long.MinValue);
21 public static readonly TimeSpan Zero = new TimeSpan (0L);
23 public const long TicksPerDay = 864000000000L;
24 public const long TicksPerHour = 36000000000L;
25 public const long TicksPerMillisecond = 10000L;
26 public const long TicksPerMinute = 600000000L;
27 public const long TicksPerSecond = 10000000L;
31 public TimeSpan (long value)
36 public TimeSpan (int hours, int minutes, int seconds)
37 : this(false, 0, hours, minutes, seconds, 0, 0)
41 public TimeSpan (int days, int hours, int minutes, int seconds)
42 : this(false, days, hours, minutes, seconds, 0, 0)
46 public TimeSpan (int days, int hours, int minutes, int seconds, int milliseconds)
47 : this(false, days, hours, minutes, seconds, milliseconds, 0)
51 internal TimeSpan (bool sign, int days, int hours, int minutes, int seconds, int milliseconds, long ticks)
54 _ticks = TicksPerDay * days +
55 TicksPerHour * hours +
56 TicksPerMinute * minutes +
57 TicksPerSecond * seconds +
58 TicksPerMillisecond * milliseconds +
68 return (int) (_ticks / TicksPerDay);
74 return (int) (_ticks % TicksPerDay / TicksPerHour);
78 public int Milliseconds {
80 return (int) (_ticks % TicksPerSecond / TicksPerMillisecond);
86 return (int) (_ticks % TicksPerHour / TicksPerMinute);
92 return (int) (_ticks % TicksPerMinute / TicksPerSecond);
102 public double TotalDays {
104 return (double) _ticks / TicksPerDay;
108 public double TotalHours {
110 return (double) _ticks / TicksPerHour;
114 public double TotalMilliseconds {
116 return (double) _ticks / TicksPerMillisecond;
120 public double TotalMinutes {
122 return (double) _ticks / TicksPerMinute;
126 public double TotalSeconds {
128 return (double) _ticks / TicksPerSecond;
132 public TimeSpan Add (TimeSpan ts)
135 return new TimeSpan (_ticks + ts.Ticks);
139 public static int Compare (TimeSpan t1, TimeSpan t2)
141 if (t1._ticks < t2._ticks) {
144 else if (t1._ticks > t2._ticks) {
152 public int CompareTo (object value)
157 if (!(value is TimeSpan)) {
158 throw new ArgumentException (Locale.GetText (
159 "Argument of System.TimeSpan.CompareTo should be a TimeSpan"));
162 return Compare(this, (TimeSpan) value);
165 public TimeSpan Duration ()
168 return new TimeSpan (Math.Abs (_ticks));
172 public override bool Equals (object value)
174 if (!(value is TimeSpan)) {
177 return Equals (this, (TimeSpan) value);
180 public static bool Equals (TimeSpan t1, TimeSpan t2)
182 return t1._ticks == t2._ticks;
185 // Implementing FromDays -> FromHours -> FromMinutes -> FromSeconds ->
186 // FromMilliseconds as done here is probably not the most efficient
188 public static TimeSpan FromDays (double value)
190 if (Double.IsNaN (value) || Double.IsNegativeInfinity (value)) {
194 if (Double.IsPositiveInfinity (value)) {
198 return new TimeSpan ((int) value,0,0,0,0) + FromHours ((value - ((int) value)) * 24);
201 public static TimeSpan FromHours (double value)
203 if (Double.IsNaN (value) || Double.IsNegativeInfinity (value)) {
207 if (Double.IsPositiveInfinity (value)) {
211 return new TimeSpan ((int) value,0,0) + FromMinutes ((value - ((int) value)) * 60);
214 public static TimeSpan FromMinutes (double value)
216 if (Double.IsNaN (value) || Double.IsNegativeInfinity (value)) {
220 if (Double.IsPositiveInfinity (value)) {
224 return new TimeSpan (0, (int) value, 0) + FromSeconds((value - ((int) value)) * 60);
227 public static TimeSpan FromSeconds (double value)
229 if (Double.IsNaN (value) || Double.IsNegativeInfinity (value)) {
233 if (Double.IsPositiveInfinity (value)) {
237 return new TimeSpan (0, 0, 0, (int) value) + FromMilliseconds((value - ((int) value)) * 1000);
241 public static TimeSpan FromMilliseconds (double value)
243 if (Double.IsNaN (value) || Double.IsNegativeInfinity (value)) {
247 if (Double.IsPositiveInfinity (value)) {
251 return new TimeSpan (0, 0, 0, 0, (int) value);
254 public static TimeSpan FromTicks (long value)
256 return new TimeSpan (value);
259 public override int GetHashCode ()
261 return _ticks.GetHashCode ();
264 public TimeSpan Negate ()
266 if (_ticks == long.MinValue)
267 throw new OverflowException ("This TimeSpan value is MinValue and cannot be negated.");
268 return new TimeSpan (-_ticks);
271 public static TimeSpan Parse (string s)
274 throw new ArgumentNullException (
275 Locale.GetText ("null reference passed to TimeSpan.Parse"));
278 Parser p = new Parser (s);
282 public TimeSpan Subtract (TimeSpan ts)
285 return new TimeSpan (_ticks - ts.Ticks);
289 public override string ToString ()
297 // We need to take absolute values of all components.
298 // Can't handle negative timespans by negating the TimeSpan
299 // as a whole. This would lead to an overflow for the
300 // degenerate case "TimeSpan.MinValue.ToString()".
302 res += Math.Abs (Days) + "." ;
305 res += string.Format ("{0:D2}:{1:D2}:{2:D2}", Math.Abs(Hours), Math.Abs(Minutes), Math.Abs(Seconds));
307 int fractional = (int) Math.Abs (_ticks % TicksPerSecond);
308 if (fractional != 0) {
309 res += string.Format (".{0:D7}", fractional);
315 public static TimeSpan operator + (TimeSpan t1, TimeSpan t2)
320 public static bool operator == (TimeSpan t1, TimeSpan t2)
322 return Compare (t1, t2) == 0;
325 public static bool operator > (TimeSpan t1, TimeSpan t2)
327 return Compare (t1, t2) == 1;
330 public static bool operator >= (TimeSpan t1, TimeSpan t2)
332 return Compare (t1, t2) != -1;
335 public static bool operator != (TimeSpan t1, TimeSpan t2)
337 return Compare (t1, t2) != 0;
340 public static bool operator < (TimeSpan t1, TimeSpan t2)
342 return Compare (t1, t2) == -1;
345 public static bool operator <= (TimeSpan t1, TimeSpan t2)
347 return Compare (t1, t2) != 1;
350 public static TimeSpan operator - (TimeSpan t1, TimeSpan t2)
352 return t1.Subtract (t2);
355 public static TimeSpan operator - (TimeSpan t)
360 public static TimeSpan operator + (TimeSpan t)
365 // Class Parser implements simple parser for TimeSpan::Parse
366 internal class Parser
372 public Parser (string src)
381 _length = _src.Length;
386 return _cur >= _length;
390 private void ThrowFormatException()
392 throw new FormatException (Locale.GetText ("Invalid format for TimeSpan.Parse"));
395 // All "Parse" functions throw a FormatException on syntax error.
396 // Their return value is semantic value of the item parsed.
398 // Range checking is spread over three different places:
399 // 1) When parsing "int" values, an exception is thrown immediately
400 // when the value parsed exceeds the maximum value for an int.
401 // 2) An explicit check is built in that checks for hours > 23 and
402 // for minutes and seconds > 59.
403 // 3) Throwing an exceptions for a final TimeSpan value > MaxValue
404 // or < MinValue is left to the TimeSpan constructor called.
406 // Parse zero or more whitespace chars.
407 private void ParseWhiteSpace ()
409 while (!AtEnd && Char.IsWhiteSpace (_src, _cur)) {
414 // Parse optional sign character.
415 private bool ParseSign ()
419 if (!AtEnd && _src[_cur] == '-') {
427 // Parse simple int value
428 private int ParseInt ()
433 while (!AtEnd && Char.IsDigit (_src, _cur)) {
435 res = res*10 + _src[_cur] - '0';
442 ThrowFormatException ();
448 // Parse optional dot
449 private bool ParseOptDot ()
455 if (_src[_cur] == '.') {
464 // Parse NON-optional colon
465 private void ParseColon ()
467 if (!AtEnd && _src[_cur] == ':') {
471 ThrowFormatException ();
475 // Parse [1..7] digits, representing fractional seconds (ticks)
476 private long ParseTicks ()
480 bool digitseen = false;
482 while ( mag > 0 && !AtEnd && Char.IsDigit (_src, _cur) ) {
483 res = res + (_src[_cur] - '0') * mag;
490 ThrowFormatException ();
496 public TimeSpan Execute ()
505 // Parse [ws][dd.]hh:mm:ss[.ff][ws]
509 if (ParseOptDot ()) {
517 minutes = ParseInt ();
519 seconds = ParseInt ();
520 if ( ParseOptDot () ) {
521 ticks = ParseTicks ();
529 ThrowFormatException ();
532 if ( hours > 23 || minutes > 59 || seconds > 59 ) {
533 throw new OverflowException (Locale.GetText (
534 "Value outside range in TimeSpan.Parse" ));
537 TimeSpan ts = new TimeSpan (sign, days, hours, minutes, seconds, 0, ticks);