// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; namespace System { // TimeSpan represents a duration of time. A TimeSpan can be negative // or positive. // // TimeSpan is internally represented as a number of ticks. A tick is equal // to 100 nanoseconds. While this maps well into units of time such as hours // and days, any periods longer than that aren't representable in a nice fashion. // For instance, a month can be between 28 and 31 days, while a year // can contain 365 or 366 days. A decade can have between 1 and 3 leap years, // depending on when you map the TimeSpan into the calendar. This is why // we do not provide Years() or Months(). // [Serializable] public readonly struct TimeSpan : IComparable, IComparable<TimeSpan>, IEquatable<TimeSpan>, ISpanFormattable, ISpanParsable<TimeSpan>, IUtf8SpanFormattable { /// <summary> /// Represents the number of nanoseconds per tick. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 100. /// </remarks> public const long NanosecondsPerTick = 100; // 100 /// <summary> /// Represents the number of ticks in 1 microsecond. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 10. /// </remarks> public const long TicksPerMicrosecond = 10; // 10 /// <summary> /// Represents the number of ticks in 1 millisecond. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 10 thousand; that is, 10,000. /// </remarks> public const long TicksPerMillisecond = TicksPerMicrosecond * 1000; // 10,000 /// <summary> /// Represents the number of ticks in 1 second. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 10 million; that is, 10,000,000. /// </remarks> public const long TicksPerSecond = TicksPerMillisecond * 1000; // 10,000,000 /// <summary> /// Represents the number of ticks in 1 minute. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 600 million; that is, 600,000,000. /// </remarks> public const long TicksPerMinute = TicksPerSecond * 60; // 600,000,000 /// <summary> /// Represents the number of ticks in 1 hour. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 36 billion; that is, 36,000,000,000. /// </remarks> public const long TicksPerHour = TicksPerMinute * 60; // 36,000,000,000 /// <summary> /// Represents the number of ticks in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 864 billion; that is, 864,000,000,000. /// </remarks> public const long TicksPerDay = TicksPerHour * 24; // 864,000,000,000 /// <summary> /// Represents the number of microseconds in 1 millisecond. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 1 thousand; that is, 1,000. /// </remarks> public const long MicrosecondsPerMillisecond = TicksPerMillisecond / TicksPerMicrosecond; // 1,000 /// <summary> /// Represents the number of microseconds in 1 second. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 1 million; that is, 1,000,000. /// </remarks> public const long MicrosecondsPerSecond = TicksPerSecond / TicksPerMicrosecond; // 1,000,000 /// <summary> /// Represents the number of microseconds in 1 minute. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 60 million; that is, 60,000,000. /// </remarks> public const long MicrosecondsPerMinute = TicksPerMinute / TicksPerMicrosecond; // 60,000,000 /// <summary> /// Represents the number of microseconds in 1 hour. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 3.6 billion; that is, 3,600,000,000. /// </remarks> public const long MicrosecondsPerHour = TicksPerHour / TicksPerMicrosecond; // 3,600,000,000 /// <summary> /// Represents the number of microseconds in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 86.4 billion; that is, 86,400,000,000. /// </remarks> public const long MicrosecondsPerDay = TicksPerDay / TicksPerMicrosecond; // 86,400,000,000 /// <summary> /// Represents the number of milliseconds in 1 second. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 1 thousand; that is, 1,000. /// </remarks> public const long MillisecondsPerSecond = TicksPerSecond / TicksPerMillisecond; // 1,000 /// <summary> /// Represents the number of milliseconds in 1 minute. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 60 thousand; that is, 60,000. /// </remarks> public const long MillisecondsPerMinute = TicksPerMinute / TicksPerMillisecond; // 60,000 /// <summary> /// Represents the number of milliseconds in 1 hour. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 3.6 million; that is, 3,600,000. /// </remarks> public const long MillisecondsPerHour = TicksPerHour / TicksPerMillisecond; // 3,600,000 /// <summary> /// Represents the number of milliseconds in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 86.4 million; that is, 86,400,000. /// </remarks> public const long MillisecondsPerDay = TicksPerDay / TicksPerMillisecond; // 86,400,000 /// <summary> /// Represents the number of seconds in 1 minute. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 60. /// </remarks> public const long SecondsPerMinute = TicksPerMinute / TicksPerSecond; // 60 /// <summary> /// Represents the number of seconds in 1 hour. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 3.6 thousand; that is, 3,600. /// </remarks> public const long SecondsPerHour = TicksPerHour / TicksPerSecond; // 3,600 /// <summary> /// Represents the number of seconds in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 86.4 thousand; that is, 86,400. /// </remarks> public const long SecondsPerDay = TicksPerDay / TicksPerSecond; // 86,400 /// <summary> /// Represents the number of minutes in 1 hour. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 60. /// </remarks> public const long MinutesPerHour = TicksPerHour / TicksPerMinute; // 60 /// <summary> /// Represents the number of minutes in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 1440. /// </remarks> public const long MinutesPerDay = TicksPerDay / TicksPerMinute; // 1,440 /// <summary> /// Represents the number of hours in 1 day. This field is constant. /// </summary> /// <remarks> /// The value of this constant is 24. /// </remarks> public const int HoursPerDay = (int)(TicksPerDay / TicksPerHour); // 24 internal const long MinTicks = long.MinValue; // -9,223,372,036,854,775,808 internal const long MaxTicks = long.MaxValue; // +9,223,372,036,854,775,807 internal const long MinMicroseconds = MinTicks / TicksPerMicrosecond; // - 922,337,203,685,477,580 internal const long MaxMicroseconds = MaxTicks / TicksPerMicrosecond; // + 922,337,203,685,477,580 internal const long MinMilliseconds = MinTicks / TicksPerMillisecond; // - 922,337,203,685,477 internal const long MaxMilliseconds = MaxTicks / TicksPerMillisecond; // + 922,337,203,685,477 internal const long MinSeconds = MinTicks / TicksPerSecond; // - 922,337,203,685 internal const long MaxSeconds = MaxTicks / TicksPerSecond; // + 922,337,203,685 internal const long MinMinutes = MinTicks / TicksPerMinute; // - 15,372,286,728 internal const long MaxMinutes = MaxTicks / TicksPerMinute; // + 15,372,286,728 internal const long MinHours = MinTicks / TicksPerHour; // - 256,204,778 internal const long MaxHours = MaxTicks / TicksPerHour; // + 256,204,778 internal const long MinDays = MinTicks / TicksPerDay; // - 10,675,199 internal const long MaxDays = MaxTicks / TicksPerDay; // + 10,675,199 internal const long TicksPerTenthSecond = TicksPerMillisecond * 100; public static readonly TimeSpan Zero = new TimeSpan(0); public static readonly TimeSpan MaxValue = new TimeSpan(MaxTicks); public static readonly TimeSpan MinValue = new TimeSpan(MinTicks); // internal so that DateTime doesn't have to call an extra get // method for some arithmetic operations. internal readonly long _ticks; // Do not rename (binary serialization) public TimeSpan(long ticks) { _ticks = ticks; } public TimeSpan(int hours, int minutes, int seconds) { _ticks = TimeToTicks(hours, minutes, seconds); } public TimeSpan(int days, int hours, int minutes, int seconds) : this(days, hours, minutes, seconds, 0) { } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// days, hours, minutes, seconds, and milliseconds. /// </summary> /// <param name="days">Number of days.</param> /// <param name="hours">Number of hours.</param> /// <param name="minutes">Number of minutes.</param> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <remarks> /// The specified <paramref name="days"/>, <paramref name="hours"/>, <paramref name="minutes"/>, <paramref name="seconds"/> /// and <paramref name="milliseconds"/> are converted to ticks, and that value initializes this instance. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds) : this(days, hours, minutes, seconds, milliseconds, 0) { } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// days, hours, minutes, seconds, and milliseconds. /// </summary> /// <param name="days">Number of days.</param> /// <param name="hours">Number of hours.</param> /// <param name="minutes">Number of minutes.</param> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <remarks> /// The specified <paramref name="days"/>, <paramref name="hours"/>, <paramref name="minutes"/>, <paramref name="seconds"/> /// <paramref name="milliseconds"/> and <paramref name="microseconds"/> are converted to ticks, and that value initializes this instance. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds, int microseconds) { long totalMicroseconds = (days * MicrosecondsPerDay) + (hours * MicrosecondsPerHour) + (minutes * MicrosecondsPerMinute) + (seconds * MicrosecondsPerSecond) + (milliseconds * MicrosecondsPerMillisecond) + microseconds; if ((totalMicroseconds > MaxMicroseconds) || (totalMicroseconds < MinMicroseconds)) { ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); } _ticks = totalMicroseconds * TicksPerMicrosecond; } public long Ticks => _ticks; public int Days => (int)(_ticks / TicksPerDay); public int Hours => (int)(_ticks / TicksPerHour % HoursPerDay); public int Milliseconds => (int)(_ticks / TicksPerMillisecond % MillisecondsPerSecond); /// <summary> /// Gets the microseconds component of the time interval represented by the current <see cref="TimeSpan"/> structure. /// </summary> /// <remarks> /// The <see cref="Microseconds"/> property represents whole microseconds, whereas the /// <see cref="TotalMicroseconds"/> property represents whole and fractional microseconds. /// </remarks> public int Microseconds => (int)(_ticks / TicksPerMicrosecond % MicrosecondsPerMillisecond); /// <summary> /// Gets the nanoseconds component of the time interval represented by the current <see cref="TimeSpan"/> structure. /// </summary> /// <remarks> /// The <see cref="Nanoseconds"/> property represents whole nanoseconds, whereas the /// <see cref="TotalNanoseconds"/> property represents whole and fractional nanoseconds. /// </remarks> public int Nanoseconds => (int)(_ticks % TicksPerMicrosecond * NanosecondsPerTick); public int Minutes => (int)(_ticks / TicksPerMinute % MinutesPerHour); public int Seconds => (int)(_ticks / TicksPerSecond % SecondsPerMinute); public double TotalDays => (double)_ticks / TicksPerDay; public double TotalHours => (double)_ticks / TicksPerHour; public double TotalMilliseconds { get { double temp = (double)_ticks / TicksPerMillisecond; if (temp > MaxMilliseconds) { return MaxMilliseconds; } if (temp < MinMilliseconds) { return MinMilliseconds; } return temp; } } /// <summary> /// Gets the value of the current <see cref="TimeSpan"/> structure expressed in whole and fractional microseconds. /// </summary> /// <remarks> /// This property converts the value of this instance from ticks to microseconds. /// This number might include whole and fractional microseconds. /// /// The <see cref="TotalMicroseconds"/> property represents whole and fractional microseconds, /// whereas the <see cref="Microseconds"/> property represents whole microseconds. /// </remarks> public double TotalMicroseconds => (double)_ticks / TicksPerMicrosecond; /// <summary> /// Gets the value of the current <see cref="TimeSpan"/> structure expressed in whole and fractional nanoseconds. /// </summary> /// <remarks> /// This property converts the value of this instance from ticks to nanoseconds. /// This number might include whole and fractional nanoseconds. /// /// The <see cref="TotalNanoseconds"/> property represents whole and fractional nanoseconds, /// whereas the <see cref="Nanoseconds"/> property represents whole nanoseconds. /// </remarks> public double TotalNanoseconds => (double)_ticks * NanosecondsPerTick; public double TotalMinutes => (double)_ticks / TicksPerMinute; public double TotalSeconds => (double)_ticks / TicksPerSecond; public TimeSpan Add(TimeSpan ts) => this + ts; // Compares two TimeSpan values, returning an integer that indicates their // relationship. // public static int Compare(TimeSpan t1, TimeSpan t2) => t1._ticks.CompareTo(t2._ticks); // Returns a value less than zero if this object public int CompareTo(object? value) { if (value is null) { return 1; } if (value is TimeSpan other) { return CompareTo(other); } throw new ArgumentException(SR.Arg_MustBeTimeSpan); } public int CompareTo(TimeSpan value) => Compare(this, value); public static TimeSpan FromDays(double value) => Interval(value, TicksPerDay); public TimeSpan Duration() { if (_ticks == MinTicks) { ThrowHelper.ThrowOverflowException_TimeSpanDuration(); } return new TimeSpan(_ticks >= 0 ? _ticks : -_ticks); } public override bool Equals([NotNullWhen(true)] object? value) => (value is TimeSpan other) && Equals(other); public bool Equals(TimeSpan obj) => Equals(this, obj); public static bool Equals(TimeSpan t1, TimeSpan t2) => t1 == t2; public override int GetHashCode() => _ticks.GetHashCode(); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TimeSpan FromUnits(long units, long ticksPerUnit, long minUnits, long maxUnits) { System.Diagnostics.Debug.Assert(minUnits < 0); System.Diagnostics.Debug.Assert(maxUnits > 0); if (units > maxUnits || units < minUnits) { ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); } return TimeSpan.FromTicks(units * ticksPerUnit); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// days. /// </summary> /// <param name="days">Number of days.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of days.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromDays(int days) => FromUnits(days, TicksPerDay, MinDays, MaxDays); /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// days, hours, minutes, seconds, milliseconds, and microseconds. /// </summary> /// <param name="days">Number of days.</param> /// <param name="hours">Number of hours.</param> /// <param name="minutes">Number of minutes.</param> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of days, hours, minutes, seconds, milliseconds, and microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromDays(int days, int hours = 0, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) { Int128 totalMicroseconds = Math.BigMul(days, MicrosecondsPerDay) + Math.BigMul(hours, MicrosecondsPerHour) + Math.BigMul(minutes, MicrosecondsPerMinute) + Math.BigMul(seconds, MicrosecondsPerSecond) + Math.BigMul(milliseconds, MicrosecondsPerMillisecond) + microseconds; return FromMicroseconds(totalMicroseconds); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// hours. /// </summary> /// <param name="hours">Number of hours.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of hours.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromHours(int hours) => FromUnits(hours, TicksPerHour, MinHours, MaxHours); /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// hours, minutes, seconds, milliseconds, and microseconds. /// </summary> /// <param name="hours">Number of hours.</param> /// <param name="minutes">Number of minutes.</param> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of hours, minutes, seconds, milliseconds, and microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromHours(int hours, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) { Int128 totalMicroseconds = Math.BigMul(hours, MicrosecondsPerHour) + Math.BigMul(minutes, MicrosecondsPerMinute) + Math.BigMul(seconds, MicrosecondsPerSecond) + Math.BigMul(milliseconds, MicrosecondsPerMillisecond) + microseconds; return FromMicroseconds(totalMicroseconds); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// minutes. /// </summary> /// <param name="minutes">Number of minutes.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of minutes.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromMinutes(long minutes) => FromUnits(minutes, TicksPerMinute, MinMinutes, MaxMinutes); /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// minutes, seconds, milliseconds, and microseconds. /// </summary> /// <param name="minutes">Number of minutes.</param> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of minutes, seconds, milliseconds, and microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromMinutes(long minutes, long seconds = 0, long milliseconds = 0, long microseconds = 0) { Int128 totalMicroseconds = Math.BigMul(minutes, MicrosecondsPerMinute) + Math.BigMul(seconds, MicrosecondsPerSecond) + Math.BigMul(milliseconds, MicrosecondsPerMillisecond) + microseconds; return FromMicroseconds(totalMicroseconds); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// seconds. /// </summary> /// <param name="seconds">Number of seconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of seconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromSeconds(long seconds) => FromUnits(seconds, TicksPerSecond, MinSeconds, MaxSeconds); /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// seconds, milliseconds, and microseconds. /// </summary> /// <param name="seconds">Number of seconds.</param> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of seconds, milliseconds, and microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromSeconds(long seconds, long milliseconds = 0, long microseconds = 0) { Int128 totalMicroseconds = Math.BigMul(seconds, MicrosecondsPerSecond) + Math.BigMul(milliseconds, MicrosecondsPerMillisecond) + microseconds; return FromMicroseconds(totalMicroseconds); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// milliseconds. /// </summary> /// <param name="milliseconds">Number of milliseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of milliseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameter specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromMilliseconds(long milliseconds) => FromUnits(milliseconds, TicksPerMillisecond, MinMilliseconds, MaxMilliseconds); /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// milliseconds, and microseconds. /// </summary> /// <param name="milliseconds">Number of milliseconds.</param> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of milliseconds, and microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromMilliseconds(long milliseconds, long microseconds) { Int128 totalMicroseconds = Math.BigMul(milliseconds, MicrosecondsPerMillisecond) + microseconds; return FromMicroseconds(totalMicroseconds); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TimeSpan FromMicroseconds(Int128 microseconds) { if ((microseconds > MaxMicroseconds) || (microseconds < MinMicroseconds)) { ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); } long ticks = (long)microseconds * TicksPerMicrosecond; return TimeSpan.FromTicks(ticks); } /// <summary> /// Initializes a new instance of the <see cref="TimeSpan"/> structure to a specified number of /// microseconds. /// </summary> /// <param name="microseconds">Number of microseconds.</param> /// <returns>Returns a <see cref="TimeSpan"/> that represents a specified number of microseconds.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// The parameters specify a <see cref="TimeSpan"/> value less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/> /// </exception> public static TimeSpan FromMicroseconds(long microseconds) => FromUnits(microseconds, TicksPerMicrosecond, MinMicroseconds, MaxMicroseconds); public static TimeSpan FromHours(double value) => Interval(value, TicksPerHour); private static TimeSpan Interval(double value, double scale) { if (double.IsNaN(value)) { ThrowHelper.ThrowArgumentException_Arg_CannotBeNaN(); } return IntervalFromDoubleTicks(value * scale); } private static TimeSpan IntervalFromDoubleTicks(double ticks) { if ((ticks > MaxTicks) || (ticks < MinTicks) || double.IsNaN(ticks)) { ThrowHelper.ThrowOverflowException_TimeSpanTooLong(); } if (ticks == MaxTicks) { return MaxValue; } return new TimeSpan((long)ticks); } public static TimeSpan FromMilliseconds(double value) => Interval(value, TicksPerMillisecond); /// <summary> /// Returns a <see cref="TimeSpan"/> that represents a specified number of microseconds. /// </summary> /// <param name="value">A number of microseconds.</param> /// <returns>An object that represents <paramref name="value"/>.</returns> /// <exception cref="OverflowException"> /// <paramref name="value"/> is less than <see cref="MinValue"/> or greater than <see cref="MaxValue"/>. /// /// -or- /// /// <paramref name="value"/> is <see cref="double.PositiveInfinity"/> /// /// -or- /// /// <paramref name="value"/> is <see cref="double.NegativeInfinity"/> /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="value"/> is equal to <see cref="double.NaN"/>. /// </exception> public static TimeSpan FromMicroseconds(double value) => Interval(value, TicksPerMicrosecond); public static TimeSpan FromMinutes(double value) => Interval(value, TicksPerMinute); public TimeSpan Negate() => -this; public static TimeSpan FromSeconds(double value) => Interval(value, TicksPerSecond); public TimeSpan Subtract(TimeSpan ts) => this - ts; public TimeSpan Multiply(double factor) => this * factor; public TimeSpan Divide(double divisor) => this / divisor; public double Divide(TimeSpan ts) => this / ts; public static TimeSpan FromTicks(long value) => new TimeSpan(value); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long TimeToTicks(int hour, int minute, int second) { // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31, // which is less than 2^44, meaning we won't overflow totalSeconds. long totalSeconds = (hour * SecondsPerHour) + (minute * SecondsPerMinute) + second; if ((totalSeconds > MaxSeconds) || (totalSeconds < MinSeconds)) { ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); } return totalSeconds * TicksPerSecond; } // See System.Globalization.TimeSpanParse and System.Globalization.TimeSpanFormat #region ParseAndFormat private static void ValidateStyles(TimeSpanStyles style) { if (style is not TimeSpanStyles.None and not TimeSpanStyles.AssumeNegative) { ThrowHelper.ThrowArgumentException_InvalidTimeSpanStyles(); } } public static TimeSpan Parse(string s) { /* Constructs a TimeSpan from a string. Leading and trailing white space characters are allowed. */ ArgumentNullException.ThrowIfNull(s, ExceptionArgument.input); return TimeSpanParse.Parse(s, null); } public static TimeSpan Parse(string input, IFormatProvider? formatProvider) { if (input is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); } return TimeSpanParse.Parse(input, formatProvider); } public static TimeSpan Parse(ReadOnlySpan<char> input, IFormatProvider? formatProvider = null) => TimeSpanParse.Parse(input, formatProvider); public static TimeSpan ParseExact(string input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string format, IFormatProvider? formatProvider) { ArgumentNullException.ThrowIfNull(input, ExceptionArgument.input); ArgumentNullException.ThrowIfNull(format, ExceptionArgument.format); return TimeSpanParse.ParseExact(input, format, formatProvider, TimeSpanStyles.None); } public static TimeSpan ParseExact(string input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string[] formats, IFormatProvider? formatProvider) { if (input is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); } return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None); } public static TimeSpan ParseExact(string input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string format, IFormatProvider? formatProvider, TimeSpanStyles styles) { ValidateStyles(styles); ArgumentNullException.ThrowIfNull(input, ExceptionArgument.input); ArgumentNullException.ThrowIfNull(format, ExceptionArgument.format); return TimeSpanParse.ParseExact(input, format, formatProvider, styles); } public static TimeSpan ParseExact(ReadOnlySpan<char> input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) { ValidateStyles(styles); return TimeSpanParse.ParseExact(input, format, formatProvider, styles); } public static TimeSpan ParseExact(string input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles) { ValidateStyles(styles); ArgumentNullException.ThrowIfNull(input, ExceptionArgument.input); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } public static TimeSpan ParseExact(ReadOnlySpan<char> input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles = TimeSpanStyles.None) { ValidateStyles(styles); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } public static bool TryParse([NotNullWhen(true)] string? s, out TimeSpan result) { if (s is null) { result = default; return false; } return TimeSpanParse.TryParse(s, null, out result); } public static bool TryParse(ReadOnlySpan<char> s, out TimeSpan result) => TimeSpanParse.TryParse(s, null, out result); public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, out TimeSpan result) { if (input is null) { result = default; return false; } return TimeSpanParse.TryParse(input, formatProvider, out result); } public static bool TryParse(ReadOnlySpan<char> input, IFormatProvider? formatProvider, out TimeSpan result) => TimeSpanParse.TryParse(input, formatProvider, out result); public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string? format, IFormatProvider? formatProvider, out TimeSpan result) { if (input is null || format is null) { result = default; return false; } return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); } public static bool TryParseExact(ReadOnlySpan<char> input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] ReadOnlySpan<char> format, IFormatProvider? formatProvider, out TimeSpan result) => TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { if (input is null) { result = default; return false; } return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } public static bool TryParseExact(ReadOnlySpan<char> input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) => TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string? format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles); if (input is null || format is null) { result = default; return false; } return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } public static bool TryParseExact(ReadOnlySpan<char> input, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles); return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles); if (input is null) { result = default; return false; } return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); } public static bool TryParseExact(ReadOnlySpan<char> input, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles); return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); } public override string ToString() => TimeSpanFormat.FormatC(this); public string ToString([StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string? format) => TimeSpanFormat.Format(this, format, null); public string ToString([StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] string? format, IFormatProvider? formatProvider) => TimeSpanFormat.Format(this, format, formatProvider); public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] ReadOnlySpan<char> format = default, IFormatProvider? formatProvider = null) => TimeSpanFormat.TryFormat(this, destination, out charsWritten, format, formatProvider); /// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" /> public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.TimeSpanFormat)] ReadOnlySpan<char> format = default, IFormatProvider? formatProvider = null) => TimeSpanFormat.TryFormat(this, utf8Destination, out bytesWritten, format, formatProvider); #endregion public static TimeSpan operator -(TimeSpan t) { if (t._ticks == MinTicks) { ThrowHelper.ThrowOverflowException_NegateTwosCompNum(); } return new TimeSpan(-t._ticks); } public static TimeSpan operator -(TimeSpan t1, TimeSpan t2) { long result = t1._ticks - t2._ticks; long t1Sign = t1._ticks >> 63; if ((t1Sign != (t2._ticks >> 63)) && (t1Sign != (result >> 63))) { // Overflow if signs of operands was different and result's sign was opposite. // >> 63 gives the sign bit (either 64 1's or 64 0's). ThrowHelper.ThrowOverflowException_TimeSpanTooLong(); } return new TimeSpan(result); } public static TimeSpan operator +(TimeSpan t) => t; public static TimeSpan operator +(TimeSpan t1, TimeSpan t2) { long result = t1._ticks + t2._ticks; long t1Sign = t1._ticks >> 63; if ((t1Sign == (t2._ticks >> 63)) && (t1Sign != (result >> 63))) { // Overflow if signs of operands was identical and result's sign was opposite. // >> 63 gives the sign bit (either 64 1's or 64 0's). ThrowHelper.ThrowOverflowException_TimeSpanTooLong(); } return new TimeSpan(result); } /// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_Multiply(TSelf, TOther)" /> public static TimeSpan operator *(TimeSpan timeSpan, double factor) { if (double.IsNaN(factor)) { ThrowHelper.ThrowArgumentException_Arg_CannotBeNaN(ExceptionArgument.factor); } // Rounding to the nearest tick is as close to the result we would have with unlimited // precision as possible, and so likely to have the least potential to surprise. double ticks = Math.Round(timeSpan.Ticks * factor); return IntervalFromDoubleTicks(ticks); } /// <inheritdoc cref="IMultiplyOperators{TSelf, TOther, TResult}.op_Multiply(TSelf, TOther)" /> public static TimeSpan operator *(double factor, TimeSpan timeSpan) => timeSpan * factor; /// <inheritdoc cref="IDivisionOperators{TSelf, TOther, TResult}.op_Division(TSelf, TOther)" /> public static TimeSpan operator /(TimeSpan timeSpan, double divisor) { if (double.IsNaN(divisor)) { ThrowHelper.ThrowArgumentException_Arg_CannotBeNaN(ExceptionArgument.divisor); } double ticks = Math.Round(timeSpan.Ticks / divisor); return IntervalFromDoubleTicks(ticks); } // Using floating-point arithmetic directly means that infinities can be returned, which is reasonable // if we consider TimeSpan.FromHours(1) / TimeSpan.Zero asks how many zero-second intervals there are in // an hour for which infinity is the mathematic correct answer. Having TimeSpan.Zero / TimeSpan.Zero return NaN // is perhaps less useful, but no less useful than an exception. /// <inheritdoc cref="IDivisionOperators{TSelf, TOther, TResult}.op_Division(TSelf, TOther)" /> public static double operator /(TimeSpan t1, TimeSpan t2) => t1.Ticks / (double)t2.Ticks; /// <inheritdoc cref="IEqualityOperators{TSelf, TOther, TResult}.op_Equality(TSelf, TOther)" /> public static bool operator ==(TimeSpan t1, TimeSpan t2) => t1._ticks == t2._ticks; /// <inheritdoc cref="IEqualityOperators{TSelf, TOther, TResult}.op_Inequality(TSelf, TOther)" /> public static bool operator !=(TimeSpan t1, TimeSpan t2) => t1._ticks != t2._ticks; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThan(TSelf, TOther)" /> public static bool operator <(TimeSpan t1, TimeSpan t2) => t1._ticks < t2._ticks; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_LessThanOrEqual(TSelf, TOther)" /> public static bool operator <=(TimeSpan t1, TimeSpan t2) => t1._ticks <= t2._ticks; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThan(TSelf, TOther)" /> public static bool operator >(TimeSpan t1, TimeSpan t2) => t1._ticks > t2._ticks; /// <inheritdoc cref="IComparisonOperators{TSelf, TOther, TResult}.op_GreaterThanOrEqual(TSelf, TOther)" /> public static bool operator >=(TimeSpan t1, TimeSpan t2) => t1._ticks >= t2._ticks; } }