Fix IDE0025 (use expression body for properties)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / TimeSpan.cs
blobb4a20cde1e7aaad17cb278a86a0012af13ea1c7f
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Globalization;
6 using System.Runtime.CompilerServices;
8 namespace System
10 // TimeSpan represents a duration of time. A TimeSpan can be negative
11 // or positive.
13 // TimeSpan is internally represented as a number of milliseconds. While
14 // this maps well into units of time such as hours and days, any
15 // periods longer than that aren't representable in a nice fashion.
16 // For instance, a month can be between 28 and 31 days, while a year
17 // can contain 365 or 364 days. A decade can have between 1 and 3 leapyears,
18 // depending on when you map the TimeSpan into the calendar. This is why
19 // we do not provide Years() or Months().
21 // Note: System.TimeSpan needs to interop with the WinRT structure
22 // type Windows::Foundation:TimeSpan. These types are currently binary-compatible in
23 // memory so no custom marshalling is required. If at any point the implementation
24 // details of this type should change, or new fields added, we need to remember to add
25 // an appropriate custom ILMarshaler to keep WInRT interop scenarios enabled.
27 [Serializable]
28 public readonly struct TimeSpan : IComparable, IComparable<TimeSpan>, IEquatable<TimeSpan>, IFormattable, ISpanFormattable
30 public const long TicksPerMillisecond = 10000;
31 private const double MillisecondsPerTick = 1.0 / TicksPerMillisecond;
33 public const long TicksPerSecond = TicksPerMillisecond * 1000; // 10,000,000
34 private const double SecondsPerTick = 1.0 / TicksPerSecond; // 0.0000001
36 public const long TicksPerMinute = TicksPerSecond * 60; // 600,000,000
37 private const double MinutesPerTick = 1.0 / TicksPerMinute; // 1.6666666666667e-9
39 public const long TicksPerHour = TicksPerMinute * 60; // 36,000,000,000
40 private const double HoursPerTick = 1.0 / TicksPerHour; // 2.77777777777777778e-11
42 public const long TicksPerDay = TicksPerHour * 24; // 864,000,000,000
43 private const double DaysPerTick = 1.0 / TicksPerDay; // 1.1574074074074074074e-12
45 internal const long MaxSeconds = long.MaxValue / TicksPerSecond;
46 internal const long MinSeconds = long.MinValue / TicksPerSecond;
48 internal const long MaxMilliSeconds = long.MaxValue / TicksPerMillisecond;
49 internal const long MinMilliSeconds = long.MinValue / TicksPerMillisecond;
51 internal const long TicksPerTenthSecond = TicksPerMillisecond * 100;
53 public static readonly TimeSpan Zero = new TimeSpan(0);
55 public static readonly TimeSpan MaxValue = new TimeSpan(long.MaxValue);
56 public static readonly TimeSpan MinValue = new TimeSpan(long.MinValue);
58 // internal so that DateTime doesn't have to call an extra get
59 // method for some arithmetic operations.
60 internal readonly long _ticks; // Do not rename (binary serialization)
62 public TimeSpan(long ticks)
64 this._ticks = ticks;
67 public TimeSpan(int hours, int minutes, int seconds)
69 _ticks = TimeToTicks(hours, minutes, seconds);
72 public TimeSpan(int days, int hours, int minutes, int seconds)
73 : this(days, hours, minutes, seconds, 0)
77 public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds)
79 long totalMilliSeconds = ((long)days * 3600 * 24 + (long)hours * 3600 + (long)minutes * 60 + seconds) * 1000 + milliseconds;
80 if (totalMilliSeconds > MaxMilliSeconds || totalMilliSeconds < MinMilliSeconds)
81 throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong);
82 _ticks = (long)totalMilliSeconds * TicksPerMillisecond;
85 public long Ticks => _ticks;
87 public int Days => (int)(_ticks / TicksPerDay);
89 public int Hours => (int)((_ticks / TicksPerHour) % 24);
91 public int Milliseconds => (int)((_ticks / TicksPerMillisecond) % 1000);
93 public int Minutes => (int)((_ticks / TicksPerMinute) % 60);
95 public int Seconds => (int)((_ticks / TicksPerSecond) % 60);
97 public double TotalDays => ((double)_ticks) * DaysPerTick;
99 public double TotalHours => (double)_ticks * HoursPerTick;
101 public double TotalMilliseconds
105 double temp = (double)_ticks * MillisecondsPerTick;
106 if (temp > MaxMilliSeconds)
107 return (double)MaxMilliSeconds;
109 if (temp < MinMilliSeconds)
110 return (double)MinMilliSeconds;
112 return temp;
116 public double TotalMinutes => (double)_ticks * MinutesPerTick;
118 public double TotalSeconds => (double)_ticks * SecondsPerTick;
120 public TimeSpan Add(TimeSpan ts)
122 long result = _ticks + ts._ticks;
123 // Overflow if signs of operands was identical and result's
124 // sign was opposite.
125 // >> 63 gives the sign bit (either 64 1's or 64 0's).
126 if ((_ticks >> 63 == ts._ticks >> 63) && (_ticks >> 63 != result >> 63))
127 throw new OverflowException(SR.Overflow_TimeSpanTooLong);
128 return new TimeSpan(result);
132 // Compares two TimeSpan values, returning an integer that indicates their
133 // relationship.
135 public static int Compare(TimeSpan t1, TimeSpan t2)
137 if (t1._ticks > t2._ticks) return 1;
138 if (t1._ticks < t2._ticks) return -1;
139 return 0;
142 // Returns a value less than zero if this object
143 public int CompareTo(object? value)
145 if (value == null) return 1;
146 if (!(value is TimeSpan))
147 throw new ArgumentException(SR.Arg_MustBeTimeSpan);
148 long t = ((TimeSpan)value)._ticks;
149 if (_ticks > t) return 1;
150 if (_ticks < t) return -1;
151 return 0;
154 public int CompareTo(TimeSpan value)
156 long t = value._ticks;
157 if (_ticks > t) return 1;
158 if (_ticks < t) return -1;
159 return 0;
162 public static TimeSpan FromDays(double value)
164 return Interval(value, TicksPerDay);
167 public TimeSpan Duration()
169 if (Ticks == TimeSpan.MinValue.Ticks)
170 throw new OverflowException(SR.Overflow_Duration);
171 return new TimeSpan(_ticks >= 0 ? _ticks : -_ticks);
174 public override bool Equals(object? value)
176 if (value is TimeSpan)
178 return _ticks == ((TimeSpan)value)._ticks;
180 return false;
183 public bool Equals(TimeSpan obj)
185 return _ticks == obj._ticks;
188 public static bool Equals(TimeSpan t1, TimeSpan t2)
190 return t1._ticks == t2._ticks;
193 public override int GetHashCode()
195 return (int)_ticks ^ (int)(_ticks >> 32);
198 public static TimeSpan FromHours(double value)
200 return Interval(value, TicksPerHour);
203 private static TimeSpan Interval(double value, double scale)
205 if (double.IsNaN(value))
206 throw new ArgumentException(SR.Arg_CannotBeNaN);
207 double millis = value * scale;
208 if ((millis > long.MaxValue) || (millis < long.MinValue))
209 throw new OverflowException(SR.Overflow_TimeSpanTooLong);
210 return new TimeSpan((long)millis);
213 public static TimeSpan FromMilliseconds(double value)
215 return Interval(value, TicksPerMillisecond);
218 public static TimeSpan FromMinutes(double value)
220 return Interval(value, TicksPerMinute);
223 public TimeSpan Negate()
225 if (Ticks == TimeSpan.MinValue.Ticks)
226 throw new OverflowException(SR.Overflow_NegateTwosCompNum);
227 return new TimeSpan(-_ticks);
230 public static TimeSpan FromSeconds(double value)
232 return Interval(value, TicksPerSecond);
235 public TimeSpan Subtract(TimeSpan ts)
237 long result = _ticks - ts._ticks;
238 // Overflow if signs of operands was different and result's
239 // sign was opposite from the first argument's sign.
240 // >> 63 gives the sign bit (either 64 1's or 64 0's).
241 if ((_ticks >> 63 != ts._ticks >> 63) && (_ticks >> 63 != result >> 63))
242 throw new OverflowException(SR.Overflow_TimeSpanTooLong);
243 return new TimeSpan(result);
246 public TimeSpan Multiply(double factor) => this * factor;
248 public TimeSpan Divide(double divisor) => this / divisor;
250 public double Divide(TimeSpan ts) => this / ts;
252 public static TimeSpan FromTicks(long value)
254 return new TimeSpan(value);
257 [MethodImpl(MethodImplOptions.AggressiveInlining)]
258 internal static long TimeToTicks(int hour, int minute, int second)
260 // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31,
261 // which is less than 2^44, meaning we won't overflow totalSeconds.
262 long totalSeconds = (long)hour * 3600 + (long)minute * 60 + (long)second;
263 if (totalSeconds > MaxSeconds || totalSeconds < MinSeconds)
264 ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong();
265 return totalSeconds * TicksPerSecond;
268 // See System.Globalization.TimeSpanParse and System.Globalization.TimeSpanFormat
269 #region ParseAndFormat
270 private static void ValidateStyles(TimeSpanStyles style, string parameterName)
272 if (style != TimeSpanStyles.None && style != TimeSpanStyles.AssumeNegative)
273 throw new ArgumentException(SR.Argument_InvalidTimeSpanStyles, parameterName);
275 public static TimeSpan Parse(string s)
277 if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
278 /* Constructs a TimeSpan from a string. Leading and trailing white space characters are allowed. */
279 return TimeSpanParse.Parse(s, null);
281 public static TimeSpan Parse(string input, IFormatProvider? formatProvider)
283 if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
284 return TimeSpanParse.Parse(input, formatProvider);
286 public static TimeSpan Parse(ReadOnlySpan<char> input, IFormatProvider? formatProvider = null)
288 return TimeSpanParse.Parse(input, formatProvider);
290 public static TimeSpan ParseExact(string input, string format, IFormatProvider? formatProvider)
292 if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
293 if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
294 return TimeSpanParse.ParseExact(input, format, formatProvider, TimeSpanStyles.None);
296 public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider? formatProvider)
298 if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
299 return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None);
301 public static TimeSpan ParseExact(string input, string format, IFormatProvider? formatProvider, TimeSpanStyles styles)
303 ValidateStyles(styles, nameof(styles));
304 if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
305 if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
306 return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
309 public static TimeSpan ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None)
311 ValidateStyles(styles, nameof(styles));
312 return TimeSpanParse.ParseExact(input, format, formatProvider, styles);
314 public static TimeSpan ParseExact(string input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles)
316 ValidateStyles(styles, nameof(styles));
317 if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
318 return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles);
320 public static TimeSpan ParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None)
322 ValidateStyles(styles, nameof(styles));
323 return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles);
325 public static bool TryParse(string? s, out TimeSpan result)
327 if (s == null)
329 result = default;
330 return false;
332 return TimeSpanParse.TryParse(s, null, out result);
334 public static bool TryParse(ReadOnlySpan<char> s, out TimeSpan result)
336 return TimeSpanParse.TryParse(s, null, out result);
339 public static bool TryParse(string? input, IFormatProvider? formatProvider, out TimeSpan result)
341 if (input == null)
343 result = default;
344 return false;
346 return TimeSpanParse.TryParse(input, formatProvider, out result);
348 public static bool TryParse(ReadOnlySpan<char> input, IFormatProvider? formatProvider, out TimeSpan result)
350 return TimeSpanParse.TryParse(input, formatProvider, out result);
352 public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, out TimeSpan result)
354 if (input == null || format == null)
356 result = default;
357 return false;
359 return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result);
362 public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, out TimeSpan result)
364 return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result);
366 public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result)
368 if (input == null)
370 result = default;
371 return false;
373 return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result);
375 public static bool TryParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result)
377 return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result);
380 public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result)
382 ValidateStyles(styles, nameof(styles));
383 if (input == null || format == null)
385 result = default;
386 return false;
389 return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
392 public static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result)
394 ValidateStyles(styles, nameof(styles));
395 return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result);
397 public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result)
399 ValidateStyles(styles, nameof(styles));
400 if (input == null)
402 result = default;
403 return false;
405 return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result);
408 public static bool TryParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result)
410 ValidateStyles(styles, nameof(styles));
411 return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result);
413 public override string ToString()
415 return TimeSpanFormat.FormatC(this);
417 public string ToString(string? format)
419 return TimeSpanFormat.Format(this, format, null);
421 public string ToString(string? format, IFormatProvider? formatProvider)
423 return TimeSpanFormat.Format(this, format, formatProvider);
426 public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? formatProvider = null)
428 return TimeSpanFormat.TryFormat(this, destination, out charsWritten, format, formatProvider);
430 #endregion
432 public static TimeSpan operator -(TimeSpan t)
434 if (t._ticks == TimeSpan.MinValue._ticks)
435 throw new OverflowException(SR.Overflow_NegateTwosCompNum);
436 return new TimeSpan(-t._ticks);
439 public static TimeSpan operator -(TimeSpan t1, TimeSpan t2)
441 return t1.Subtract(t2);
444 public static TimeSpan operator +(TimeSpan t)
446 return t;
449 public static TimeSpan operator +(TimeSpan t1, TimeSpan t2)
451 return t1.Add(t2);
454 public static TimeSpan operator *(TimeSpan timeSpan, double factor)
456 if (double.IsNaN(factor))
458 throw new ArgumentException(SR.Arg_CannotBeNaN, nameof(factor));
461 // Rounding to the nearest tick is as close to the result we would have with unlimited
462 // precision as possible, and so likely to have the least potential to surprise.
463 double ticks = Math.Round(timeSpan.Ticks * factor);
464 if (ticks > long.MaxValue || ticks < long.MinValue)
466 throw new OverflowException(SR.Overflow_TimeSpanTooLong);
469 return FromTicks((long)ticks);
472 public static TimeSpan operator *(double factor, TimeSpan timeSpan) => timeSpan * factor;
474 public static TimeSpan operator /(TimeSpan timeSpan, double divisor)
476 if (double.IsNaN(divisor))
478 throw new ArgumentException(SR.Arg_CannotBeNaN, nameof(divisor));
481 double ticks = Math.Round(timeSpan.Ticks / divisor);
482 if (ticks > long.MaxValue || ticks < long.MinValue || double.IsNaN(ticks))
484 throw new OverflowException(SR.Overflow_TimeSpanTooLong);
487 return FromTicks((long)ticks);
490 // Using floating-point arithmetic directly means that infinities can be returned, which is reasonable
491 // if we consider TimeSpan.FromHours(1) / TimeSpan.Zero asks how many zero-second intervals there are in
492 // an hour for which infinity is the mathematic correct answer. Having TimeSpan.Zero / TimeSpan.Zero return NaN
493 // is perhaps less useful, but no less useful than an exception.
494 public static double operator /(TimeSpan t1, TimeSpan t2) => t1.Ticks / (double)t2.Ticks;
496 public static bool operator ==(TimeSpan t1, TimeSpan t2)
498 return t1._ticks == t2._ticks;
501 public static bool operator !=(TimeSpan t1, TimeSpan t2)
503 return t1._ticks != t2._ticks;
506 public static bool operator <(TimeSpan t1, TimeSpan t2)
508 return t1._ticks < t2._ticks;
511 public static bool operator <=(TimeSpan t1, TimeSpan t2)
513 return t1._ticks <= t2._ticks;
516 public static bool operator >(TimeSpan t1, TimeSpan t2)
518 return t1._ticks > t2._ticks;
521 public static bool operator >=(TimeSpan t1, TimeSpan t2)
523 return t1._ticks >= t2._ticks;