A TimeSpan can be defined as the difference between two DateTime objects, an interval.

For example, take the following code, which captures the current time, waits 65 seconds, captures the current time again, and computes the difference.

// Capture the current time
var start = DateTime.Now;
// Wait 65 seconds
await Task.Delay(TimeSpan.FromSeconds(65));
var stop = DateTime.Now;
// Capture the current time
var diff = stop - start;

The variable diff here is a TimeSpan.

How do we display this?

We have a number of options.

We can display it in minutes, using the TotalMinutes property, like this:

Console.WriteLine(diff.TotalMinutes);

This will print the following:

1.0833333333333333

This means that there is a complete minute (60/60), and 0.833 of a minute (5/60)

We can also display it in seconds, using the TotalSeconds property like this:

Console.WriteLine(diff.TotalSeconds);

This will print the following:

65

But what if we wanted to show both?

This requires a little more work and uses the Minutes and Seconds property. (We have discussed the difference in the post Tip - TimeSpan Minutes vs TotalMinutes)

Console.WriteLine($"{diff.Minutes} minute and {diff.Seconds} seconds");

This will print the following:

1 minute and 5 seconds

What if the duration were longer?

diff = TimeSpan.FromSeconds(4000);

We have the same challenge in terms of how to display this. We can do it in hours, in minutes, in seconds, or any combination thereof.

Console.WriteLine($"{diff.Hours} hour, {diff.Minutes} minutes and {diff.Seconds} seconds");

This prints the following:

1 hour, 6 minutes and 40 seconds

The problem arises when we pass this code a very small Timespan.

diff = TimeSpan.FromSeconds(1.5);

This prints the following:

0 hour, 0 minutes and 1 seconds

Things get complicated if there are even smaller units - the TimeSpan can also display milliseconds, microseconds, and nanoseconds.

There are also larger units; the TimeSpan can represent days.

In short, if we have TimeSpans that can be of arbitrary size, displaying them in a user-friendly way can be very problematic.

The solution to this is the Humanizer library, specifically the Humanize method.

Let us demonstrate using some simple scenarios.

var diff = TimeSpan.FromHours(180);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromHours(168);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromHours(60);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromHours(50);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromMinutes(65);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromMinutes(60);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromSeconds(65);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromSeconds(60);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromMilliseconds(1300);
Console.WriteLine(diff.Humanize());

diff = TimeSpan.FromMilliseconds(1000);
Console.WriteLine(diff.Humanize());

This will print the following:

1 week
1 week
2 days
2 days
1 hour
1 hour
1 minute
1 minute
1 second
1 second

It is technically correct, but upon closer examination, you will notice a slight loss of accuracy.

We can fix this by specifying the desired precision as a parameter to the Humanize method.

1 week, 12 hours
1 week
2 days, 12 hours
2 days, 2 hours
1 hour, 5 minutes
1 hour
1 minute, 5 seconds

The 2 here indicates we want the time in its two largest representative units.

It can be as accurate as you like. If the data were even more granular, we can specify 3.

diff = TimeSpan.FromHours(180.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromHours(168.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromHours(60.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromHours(50.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromMinutes(65.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromMinutes(60.5);
Console.WriteLine(diff.Humanize(3));

diff = TimeSpan.FromSeconds(65.5);
Console.WriteLine(diff.Humanize(3));

This will print the following:

1 week, 12 hours, 30 minutes
1 week, 30 minutes
2 days, 12 hours, 30 minutes
2 days, 2 hours, 30 minutes
1 hour, 5 minutes, 30 seconds
1 hour, 30 seconds
1 minute, 5 seconds, 500 milliseconds

As an added bonus, Humanizer takes care of the correct pluralization of the time units, as discussed in the post Pet Peeve - Properly Pluralizing Counts In C# & .NET.

Another bonus is that the TimeSpan allows the display of larger intervals - weeks, months, years.

TLDR

The Humanizer package contains extension methods that can be very useful for displaying TimeSpan in a human-readable way.

The code is in my GitHub.

Happy hacking!