< Summary

Information
Class: AmbientServices.Utilities.TimeSpanUtilities
Assembly: AmbientServices
File(s): /home/runner/work/AmbientServices/AmbientServices/AmbientServices/Utilities/TimeSpanUtilities.cs
Tag: 332_35464845198
Line coverage
93%
Covered lines: 29
Uncovered lines: 2
Coverable lines: 31
Total lines: 123
Line coverage: 93.5%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
GCD(...)100%66100%
TimeSpanTicksToStopwatchTicks(...)100%11100%
StopwatchTicksToTimeSpanTicks(...)100%1150%
StopwatchTimestampToDateTime(...)100%11100%
DateTimeToStopwatchTimestamp(...)100%11100%

File(s)

/home/runner/work/AmbientServices/AmbientServices/AmbientServices/Utilities/TimeSpanUtilities.cs

#LineLine coverage
 1using System;
 2using System.Diagnostics;
 3using System.Threading;
 4
 5namespace AmbientServices.Utilities;
 6
 7/// <summary>
 8/// A static class that contains utility functions for <see cref="System.TimeSpan"/>.
 9/// </summary>
 10/// <remarks>
 11/// <pitch>Precise conversion between the library's three time representations — <see cref="TimeSpan"/> ticks, <see cref
 12/// <pledge>Tick-rate conversions are exact whenever the integer math fits in a <see cref="long"/> and lose at most doub
 13/// <plan>The static initializer reduces the <see cref="TimeSpan"/> and <see cref="Stopwatch.Frequency"/> tick rates by 
 14/// </remarks>
 15internal static class TimeSpanUtilities
 16{
 17    internal static readonly long TimeSpanToStopwatchMultiplier;
 18    internal static readonly long TimeSpanToStopwatchDivisor;
 19    private static readonly double TimeSpanToStopwatchRatio;
 20    internal static readonly long StopwatchToTimeSpanMultiplier;
 21    internal static readonly long StopwatchToTimeSpanDivisor;
 22    private static readonly double StopwatchToTimeSpanRatio;
 23    private static readonly long BaselineStopwatchTimestamp;
 24    private static readonly long BaselineDateTimeTicks;
 25#pragma warning disable CA1810  // it should be faster in this case to do it this way because the values depend on each 
 26    static TimeSpanUtilities()
 27#pragma warning restore CA1810
 28    {
 329        ulong timeSpanTicksPerSecond = TimeSpan.TicksPerSecond;
 330        ulong stopwatchTicksPerSecond = (ulong)Stopwatch.Frequency;
 31        // adjust the multipliers and divisors to reduce the range of values that will cause overflow during conversion 
 332        ulong gcd = GCD(timeSpanTicksPerSecond, stopwatchTicksPerSecond);
 333        TimeSpanToStopwatchMultiplier = (long)(stopwatchTicksPerSecond / gcd);
 334        TimeSpanToStopwatchDivisor = (long)(timeSpanTicksPerSecond / gcd);
 335        TimeSpanToStopwatchRatio = TimeSpanToStopwatchMultiplier / (double)TimeSpanToStopwatchDivisor;
 336        StopwatchToTimeSpanMultiplier = (long)(timeSpanTicksPerSecond / gcd);
 337        StopwatchToTimeSpanDivisor = (long)(stopwatchTicksPerSecond / gcd);
 338        StopwatchToTimeSpanRatio = StopwatchToTimeSpanMultiplier / (double)StopwatchToTimeSpanDivisor;
 339        BaselineStopwatchTimestamp = Stopwatch.GetTimestamp();     // note that it doesn't matter if AmbientClock is in 
 40#if DEBUG   // delay this a little bit just in case it makes a difference
 41        System.Threading.Thread.Sleep(73);
 42#endif
 43        // we can't use AmbientClock here because it probably hasn't been fully initialized yet
 344        BaselineDateTimeTicks = DateTime.UtcNow.Ticks;
 45        // make sure that nobody else gets times before these
 346        System.Threading.Thread.MemoryBarrier();
 347        TimeSpanStopwatchConversionLeastCommonMultiple = TimeSpanToStopwatchMultiplier * TimeSpanToStopwatchDivisor;
 348    }
 49    internal static ulong GCD(ulong a, ulong b)
 50    {
 351        while (a != 0 && b != 0)
 52        {
 353            if (a > b) a %= b; else b %= a;
 54        }
 355        return a | b;
 56    }
 57    /// <summary>
 58    /// Gets the smallest number of ticks than can be successfully roundtripped between stopwatch ticks and timespan tic
 59    /// </summary>
 60    internal static long TimeSpanStopwatchConversionLeastCommonMultiple { get; private set; }
 61    /// <summary>
 62    /// Converts <see cref="TimeSpan"/> ticks to <see cref="System.Diagnostics.Stopwatch"/> ticks as accurately as possi
 63    /// </summary>
 64    /// <param name="timeSpanTicks">The number of <see cref="TimeSpan"/> ticks.</param>
 65    /// <returns>The equivalent number of <see cref="System.Diagnostics.Stopwatch"/> ticks</returns>
 66    public static long TimeSpanTicksToStopwatchTicks(long timeSpanTicks)
 67    {
 68        try
 69        {
 70            checked
 71            {
 372                return timeSpanTicks * TimeSpanToStopwatchMultiplier / TimeSpanToStopwatchDivisor;
 73            }
 74        }
 75        // Coverage note: the testability of this code depends on the values of system constants which cannot be altered
 276        catch (OverflowException)
 77        {
 278            return (long)(timeSpanTicks * TimeSpanToStopwatchRatio);
 79        }
 380    }
 81    /// <summary>
 82    /// Converts <see cref="System.Diagnostics.Stopwatch"/> ticks to <see cref="TimeSpan"/> ticks as accurately as possi
 83    /// </summary>
 84    /// <param name="timeSpanTicks">The number of <see cref="System.Diagnostics.Stopwatch"/> ticks.</param>
 85    /// <returns>The equivalent number of <see cref="TimeSpan"/> ticks</returns>
 86    public static long StopwatchTicksToTimeSpanTicks(long timeSpanTicks)
 87    {
 88        try
 89        {
 90            checked
 91            {
 392                return timeSpanTicks * StopwatchToTimeSpanMultiplier / StopwatchToTimeSpanDivisor;
 93            }
 94        }
 95        // Coverage note: the testability of this code depends on the values of system constants which cannot be altered
 096        catch (OverflowException)
 97        {
 098            return (long)(timeSpanTicks * StopwatchToTimeSpanRatio);
 99        }
 3100    }
 101    /// <summary>
 102    /// Converts a stopwatch timestamp to UTC <see cref="DateTime"/> ticks.
 103    /// </summary>
 104    /// <param name="stopwatchTimestamp">A timestamp gathered from <see cref="Stopwatch.GetTimestamp()"/>.</param>
 105    /// <returns>The number of UTC <see cref="DateTime "/>ticks.</returns>
 106    public static long StopwatchTimestampToDateTime(long stopwatchTimestamp)
 107    {
 3108        long stopwatchTicksAgo = stopwatchTimestamp - BaselineStopwatchTimestamp;
 3109        long dateTimeTicksAgo = StopwatchTicksToTimeSpanTicks(stopwatchTicksAgo);
 3110        return BaselineDateTimeTicks + dateTimeTicksAgo;
 111    }
 112    /// <summary>
 113    /// Converts UTC <see cref="DateTime"/> ticks to a stopwatch timestamp.
 114    /// </summary>
 115    /// <param name="dateTimeTicks">Ticks from a UTC <see cref="DateTime"/>.</param>
 116    /// <returns>The corresponding <see cref="Stopwatch"/> timestamp.</returns>
 117    public static long DateTimeToStopwatchTimestamp(long dateTimeTicks)
 118    {
 2119        long dateTimeTicksAgo = dateTimeTicks - BaselineDateTimeTicks;
 2120        long stopwatchTicksAgo = TimeSpanTicksToStopwatchTicks(dateTimeTicksAgo);
 2121        return BaselineStopwatchTimestamp + stopwatchTicksAgo;
 122    }
 123}