Last active
February 14, 2023 19:25
-
-
Save randyburden/8186395 to your computer and use it in GitHub Desktop.
TimeSpan helper and extension method for creating a formatted string of a given TimeSpan. Supports up to microsecond resolution. Also includes unit tests.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* JavaScript-equivalent version of the C# method to get a formatted time */ | |
function getFormattedTime(elapsedMilliseconds, abbreviate, includeSeconds, includeMilliseconds) { | |
if (abbreviate == undefined) { | |
abbreviate = true; | |
} | |
if (includeSeconds == undefined) { | |
includeSeconds = true; | |
} | |
if (includeMilliseconds == undefined) { | |
includeMilliseconds = true; | |
} | |
const SECONDS = 1000; | |
const MINUTES = SECONDS * 60; | |
const HOURS = MINUTES * 60; | |
const DAYS = HOURS * 24; | |
const days = parseInt(Math.floor(elapsedMilliseconds / DAYS), 10); | |
const hours = parseInt(Math.floor((elapsedMilliseconds - (days * DAYS)) / HOURS), 10); | |
const minutes = parseInt(Math.floor((elapsedMilliseconds - (days * DAYS) - (hours * HOURS)) / MINUTES), 10); | |
const seconds = parseInt(Math.floor((elapsedMilliseconds - (days * DAYS) - (hours * HOURS) - (minutes * MINUTES)) / SECONDS), 10); | |
const milliseconds = parseInt(Math.floor(elapsedMilliseconds - (days * DAYS) - (hours * HOURS) - (minutes * MINUTES) - (seconds * SECONDS)), 10); | |
var elapsedTime = ''; | |
if (days > 0) { | |
elapsedTime += `${days} ${(abbreviate ? 'd' : days === 1 ? 'day' : 'days')}`; | |
} | |
if (hours > 0) { | |
elapsedTime += ` ${hours} ${(abbreviate ? 'hr' : hours === 1 ? 'hour' : 'hours')}`; | |
} | |
if (minutes > 0) { | |
elapsedTime += ` ${minutes} ${(abbreviate ? 'min' : minutes === 1 ? 'minute' : 'minutes')}`; | |
} | |
if (includeSeconds && seconds > 0) { | |
elapsedTime += ` ${seconds} ${(abbreviate ? 'sec' : seconds === 1 ? 'second' : 'seconds')}`; | |
} | |
if (includeSeconds && includeMilliseconds && milliseconds > 0) { | |
elapsedTime += ` ${milliseconds} ${(abbreviate ? 'ms' : milliseconds === 1 ? 'millisecond' : 'milliseconds')}`; | |
} | |
const result = elapsedTime.trim(); | |
if (!result) { | |
if (includeSeconds && includeMilliseconds) { | |
return abbreviate ? '0 ms' : '0 milliseconds'; | |
} | |
if (includeSeconds) { | |
return abbreviate ? '0 sec' : '0 seconds'; | |
} | |
return abbreviate ? '0 min' : '0 minutes'; | |
} | |
return result; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Text; | |
namespace Helpers | |
{ | |
public static class TimeSpanHelper | |
{ | |
/// <summary> | |
/// Gets a formatted string of the given <see cref="TimeSpan"/>. Supports up to microsecond resolution. | |
/// | |
/// <para> | |
/// Examples: | |
/// <list type="bullet"> | |
/// <item><description>Abbreviated: 1 d 6 hr 52 min 34 sec 556 ms</description></item> | |
/// <item><description>Not abbreviated: 1 day 6 hours 52 min 34 sec 556 ms</description></item> | |
/// </list> | |
/// </para> | |
/// </summary> | |
/// <param name="timeSpan">Duration to format.</param> | |
/// <param name="abbreviate">Indicates whether to abbreviate units of time. E.g. min or minutes. Defaults to <see langword="true" />.</param> | |
/// <param name="includeSeconds">Indicates whether to include seconds. Defaults to <see langword="true" />. If <see langword="false" /> then milliseconds and microseconds are not included. /></param> | |
/// <param name="includeMilliseconds">Indicates whether to include milliseconds. Defaults to <see langword="true" />. If <see langword="false" /> then microseconds are not included.</param> | |
/// <param name="includeMicroseconds">Indicates whether to include microseconds. Microseconds will only be displayed if duration is less than 1 millisecond. Defaults to <see langword="true" />.</param> | |
/// <returns>A string with a customized output of the elapsed time.</returns> | |
public static string ToFormattedTime( | |
this TimeSpan timeSpan, | |
bool abbreviate = true, | |
bool includeSeconds = true, | |
bool includeMilliseconds = true, | |
bool includeMicroseconds = true) | |
{ | |
return GetFormattedTime(timeSpan, abbreviate, includeSeconds, includeMilliseconds, includeMicroseconds); | |
} | |
/// <summary> | |
/// Gets a formatted string of the given <see cref="TimeSpan"/>. Supports up to microsecond resolution. | |
/// | |
/// <para> | |
/// Examples: | |
/// <list type="bullet"> | |
/// <item><description>Abbreviated: 1 d 6 hr 52 min 34 sec 556 ms</description></item> | |
/// <item><description>Not abbreviated: 1 day 6 hours 52 min 34 sec 556 ms</description></item> | |
/// </list> | |
/// </para> | |
/// </summary> | |
/// <param name="timeSpan">Duration to format.</param> | |
/// <param name="abbreviate">Indicates whether to abbreviate units of time. E.g. min or minutes. Defaults to <see langword="true" />.</param> | |
/// <param name="includeSeconds">Indicates whether to include seconds. Defaults to <see langword="true" />. If <see langword="false" /> then milliseconds and microseconds are not included. /></param> | |
/// <param name="includeMilliseconds">Indicates whether to include milliseconds. Defaults to <see langword="true" />. If <see langword="false" /> then microseconds are not included.</param> | |
/// <param name="includeMicroseconds">Indicates whether to include microseconds. Microseconds will only be displayed if duration is less than 1 millisecond. Defaults to <see langword="true" />.</param> | |
/// <returns>A string with a customized output of the elapsed time.</returns> | |
public static string GetFormattedTime( | |
TimeSpan timeSpan, | |
bool abbreviate = true, | |
bool includeSeconds = true, | |
bool includeMilliseconds = true, | |
bool includeMicroseconds = true) | |
{ | |
var elapsedTime = new StringBuilder(); | |
if (timeSpan.Days > 0) | |
{ | |
elapsedTime.Append($"{timeSpan:%d} {(abbreviate ? "d" : timeSpan.Days == 1 ? "day" : "days")}"); | |
} | |
if (timeSpan.Hours > 0) | |
{ | |
elapsedTime.Append($" {timeSpan:%h} {(abbreviate ? "hr" : timeSpan.Hours == 1 ? "hour" : "hours")}"); | |
} | |
if (timeSpan.Minutes > 0) | |
{ | |
elapsedTime.Append($" {timeSpan:%m} {(abbreviate ? "min" : timeSpan.Minutes == 1 ? "minute" : "minutes")}"); | |
} | |
if (includeSeconds && timeSpan.Seconds > 0) | |
{ | |
elapsedTime.Append($" {timeSpan:%s} {(abbreviate ? "sec" : timeSpan.Seconds == 1 ? "second" : "seconds")}"); | |
} | |
if (includeSeconds && includeMilliseconds && timeSpan.Milliseconds > 0) | |
{ | |
elapsedTime.Append($" {timeSpan:fff} {(abbreviate ? "ms" : timeSpan.Milliseconds == 1 ? "millisecond" : "milliseconds")}"); | |
} | |
else if (includeSeconds && includeMilliseconds && includeMicroseconds && timeSpan.TotalMilliseconds > 0) | |
{ | |
elapsedTime.Append($" {timeSpan.TotalMilliseconds * 1000.0} {(abbreviate ? "µs" : "microseconds")}"); | |
} | |
var result = elapsedTime.ToString().Trim(); | |
if (string.IsNullOrEmpty(result)) | |
{ | |
if (includeSeconds && includeMilliseconds) | |
{ | |
return abbreviate ? "0 ms" : "0 milliseconds"; | |
} | |
if (includeSeconds) | |
{ | |
return abbreviate ? "0 sec" : "0 seconds"; | |
} | |
return abbreviate ? "0 min" : "0 minutes"; | |
} | |
return result; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using NUnit.Framework; | |
using System; | |
namespace Tests | |
{ | |
[TestFixture] | |
public class TimeSpanHelperTests | |
{ | |
[Test] | |
public void ToFormattedTime_Should_Format() | |
{ | |
Assert.That(new TimeSpan(1, 6, 52, 34, 567).ToFormattedTime(), Is.EqualTo("1 d 6 hr 52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 6, 52, 34, 567).ToFormattedTime(), Is.EqualTo("6 hr 52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 52, 34, 567).ToFormattedTime(), Is.EqualTo("52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 0, 34, 567).ToFormattedTime(), Is.EqualTo("34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 567).ToFormattedTime(), Is.EqualTo("567 ms")); | |
Assert.That(TimeSpan.FromTicks(10).ToFormattedTime(), Is.EqualTo("1 µs")); | |
Assert.That(TimeSpan.FromTicks(1).ToFormattedTime(), Is.EqualTo("0.1 µs")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 0).ToFormattedTime(), Is.EqualTo("0 ms")); | |
} | |
[Test] | |
public void ToFormattedTime_Should_Have_Option_To_Not_Abbreviate() | |
{ | |
Assert.That(new TimeSpan(1, 6, 52, 34, 567).ToFormattedTime(abbreviate: false), Is.EqualTo("1 day 6 hours 52 minutes 34 seconds 567 milliseconds")); | |
Assert.That(new TimeSpan(0, 6, 52, 34, 567).ToFormattedTime(abbreviate: false), Is.EqualTo("6 hours 52 minutes 34 seconds 567 milliseconds")); | |
Assert.That(new TimeSpan(0, 0, 52, 34, 567).ToFormattedTime(abbreviate: false), Is.EqualTo("52 minutes 34 seconds 567 milliseconds")); | |
Assert.That(new TimeSpan(0, 0, 0, 34, 567).ToFormattedTime(abbreviate: false), Is.EqualTo("34 seconds 567 milliseconds")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 567).ToFormattedTime(abbreviate: false), Is.EqualTo("567 milliseconds")); | |
Assert.That(TimeSpan.FromTicks(10).ToFormattedTime(abbreviate: false), Is.EqualTo("1 microseconds")); | |
Assert.That(TimeSpan.FromTicks(1).ToFormattedTime(abbreviate: false), Is.EqualTo("0.1 microseconds")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 0).ToFormattedTime(abbreviate: false), Is.EqualTo("0 milliseconds")); | |
} | |
[Test] | |
public void ToFormattedTime_Should_Have_Option_To_Not_Include_Microseconds() | |
{ | |
Assert.That(new TimeSpan(1, 6, 52, 34, 567).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("1 d 6 hr 52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 6, 52, 34, 567).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("6 hr 52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 52, 34, 567).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("52 min 34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 0, 34, 567).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("34 sec 567 ms")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 567).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("567 ms")); | |
Assert.That(TimeSpan.FromTicks(10).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("0 ms")); | |
Assert.That(TimeSpan.FromTicks(1).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("0 ms")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 0).ToFormattedTime(includeMicroseconds: false), Is.EqualTo("0 ms")); | |
} | |
[Test] | |
public void ToFormattedTime_Should_Have_Option_To_Not_Include_Milliseconds() | |
{ | |
Assert.That(new TimeSpan(1, 6, 52, 34, 567).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("1 d 6 hr 52 min 34 sec")); | |
Assert.That(new TimeSpan(0, 6, 52, 34, 567).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("6 hr 52 min 34 sec")); | |
Assert.That(new TimeSpan(0, 0, 52, 34, 567).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("52 min 34 sec")); | |
Assert.That(new TimeSpan(0, 0, 0, 34, 567).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("34 sec")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 567).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("0 sec")); | |
Assert.That(TimeSpan.FromTicks(10).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("0 sec")); | |
Assert.That(TimeSpan.FromTicks(1).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("0 sec")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 0).ToFormattedTime(includeMilliseconds: false), Is.EqualTo("0 sec")); | |
} | |
[Test] | |
public void ToFormattedTime_Should_Have_Option_To_Not_Include_Seconds() | |
{ | |
Assert.That(new TimeSpan(1, 6, 52, 34, 567).ToFormattedTime(includeSeconds: false), Is.EqualTo("1 d 6 hr 52 min")); | |
Assert.That(new TimeSpan(0, 6, 52, 34, 567).ToFormattedTime(includeSeconds: false), Is.EqualTo("6 hr 52 min")); | |
Assert.That(new TimeSpan(0, 0, 52, 34, 567).ToFormattedTime(includeSeconds: false), Is.EqualTo("52 min")); | |
Assert.That(new TimeSpan(0, 0, 0, 34, 567).ToFormattedTime(includeSeconds: false), Is.EqualTo("0 min")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 567).ToFormattedTime(includeSeconds: false), Is.EqualTo("0 min")); | |
Assert.That(TimeSpan.FromTicks(10).ToFormattedTime(includeSeconds: false), Is.EqualTo("0 min")); | |
Assert.That(TimeSpan.FromTicks(1).ToFormattedTime(includeSeconds: false), Is.EqualTo("0 min")); | |
Assert.That(new TimeSpan(0, 0, 0, 0, 0).ToFormattedTime(includeSeconds: false), Is.EqualTo("0 min")); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I still love using this gist. Thanks for sharing quality content, Randy!