using System; using OmiLAXR.Extensions; namespace OmiLAXR.Types { public struct Duration : IComparable { private const double ComparisonTolerance = 0.00000001; public enum DurationUnit { Milliseconds, Seconds, Minutes, Hours, Days } /// The duration value. public double Value { get; private set; } /// The unit of the duration (e.g., seconds, minutes). public DurationUnit Unit { get; private set; } /// /// Initializes a new instance of the class. /// /// The duration value. /// The unit of the duration (e.g., seconds, minutes). public Duration(double value, DurationUnit unit) { Value = value; Unit = unit; } /// /// Creates a Duration from a given number of milliseconds. /// /// The duration in milliseconds. /// A new Duration representing the given milliseconds. public static Duration FromMilliseconds(double ms) => new Duration(ms, DurationUnit.Milliseconds); /// /// Creates a Duration from a given number of seconds. /// /// The duration in seconds. /// A new Duration representing the given seconds. public static Duration FromSeconds(double seconds) => new Duration(seconds, DurationUnit.Seconds); /// /// Creates a Duration from a given number of minutes. /// /// The duration in minutes. /// A new Duration representing the given minutes. public static Duration FromMinutes(double minutes) => new Duration(minutes, DurationUnit.Minutes); /// /// Creates a Duration from a given number of hours. /// /// The duration in hours. /// A new Duration representing the given hours. public static Duration FromHours(double hours) => new Duration(hours, DurationUnit.Hours); /// /// Creates a Duration from a given number of days. /// /// The duration in days. /// A new Duration representing the given days. public static Duration FromDays(double days) => new Duration(days, DurationUnit.Days); /// /// Converts the duration to an ISO 8601 formatted string. /// /// A string representing the duration in ISO 8601 format. public override string ToString() => ToTimeSpan().ToIso8601(); public TimeSpan ToTimeSpan() => Unit switch { DurationUnit.Milliseconds => TimeSpan.FromMilliseconds(Value), DurationUnit.Seconds => TimeSpan.FromSeconds(Value), DurationUnit.Minutes => TimeSpan.FromMinutes(Value), DurationUnit.Hours => TimeSpan.FromHours(Value), DurationUnit.Days => TimeSpan.FromDays(Value), _ => throw new ArgumentOutOfRangeException() }; /// /// Converts the duration to milliseconds (as double) to allow unit-agnostic comparison. /// /// The total duration in milliseconds. public double ToMilliseconds() => Unit switch { DurationUnit.Milliseconds => Value, DurationUnit.Seconds => Value * 1000.0, DurationUnit.Minutes => Value * 60_000.0, DurationUnit.Hours => Value * 3_600_000.0, DurationUnit.Days => Value * 86_400_000.0, _ => throw new ArgumentOutOfRangeException() }; public double ToSeconds() => ToMilliseconds() / 1000.0; public double ToMinutes() => ToMilliseconds() / 60_000.0; public double ToHours() => ToMilliseconds() / 3_600_000.0; public double ToDays() => ToMilliseconds() / 86_400_000.0; public double ToWeeks() => ToMilliseconds() / 604_800_000.0; public double ToMonths() => ToMilliseconds() / 2_629_746_000.0; public double ToYears() => ToMilliseconds() / 31_557_600_000.0; // Comparison operators for Duration vs Duration /// /// Checks if one duration is less than another. /// public static bool operator <(Duration a, Duration b) => a.ToMilliseconds() < b.ToMilliseconds() - ComparisonTolerance; /// /// Checks if one duration is less than or equal to another. /// public static bool operator <=(Duration a, Duration b) => a.ToMilliseconds() <= b.ToMilliseconds() + ComparisonTolerance; /// /// Checks if one duration is greater than another. /// public static bool operator >(Duration a, Duration b) => a.ToMilliseconds() > b.ToMilliseconds() + ComparisonTolerance; /// /// Checks if one duration is greater than or equal to another. /// public static bool operator >=(Duration a, Duration b) => a.ToMilliseconds() >= b.ToMilliseconds() - ComparisonTolerance; /// /// Checks if two durations are equal, allowing for floating-point tolerance. /// public static bool operator ==(Duration a, Duration b) => Math.Abs(a.ToMilliseconds() - b.ToMilliseconds()) < ComparisonTolerance; /// /// Checks if two durations are not equal. /// public static bool operator !=(Duration a, Duration b) => !(a == b); /// /// Checks for value equality with another object. /// public override bool Equals(object obj) => obj is Duration other && this == other; /// /// Returns a hash code based on the millisecond representation. /// public override int GetHashCode() => ToMilliseconds().GetHashCode(); /// /// Compares this duration with another for sorting purposes. /// public int CompareTo(Duration other) { var diff = ToMilliseconds() - other.ToMilliseconds(); if (Math.Abs(diff) < ComparisonTolerance) return 0; return diff < 0 ? -1 : 1; } /// /// Explicitly converts the duration to a double (in milliseconds). /// /// The duration to convert. public static explicit operator double(Duration d) => d.ToMilliseconds(); /// /// Explicitly converts the duration to a float (in milliseconds). /// /// The duration to convert. public static explicit operator float(Duration d) => (float)d.ToMilliseconds(); /// /// Implicitly creates a duration from a double interpreted as milliseconds. /// /// The millisecond value to convert. public static implicit operator Duration(double ms) => FromMilliseconds(ms); /// /// Implicitly creates a duration from a float interpreted as milliseconds. /// /// The millisecond value to convert. public static implicit operator Duration(float ms) => FromMilliseconds(ms); } }