How can I String.Format a TimeSpan object with a custom format in .NET?

C#.NetStringTimeFormatting

C# Problem Overview


What is the recommended way of formatting TimeSpan objects into a string with a custom format?

C# Solutions


Solution 1 - C#

Please note: this answer is for .Net 4.0 and above. If you want to format a TimeSpan in .Net 3.5 or below please see JohannesH's answer.

Custom TimeSpan format strings were introduced in .Net 4.0. You can find a full reference of available format specifiers at the MSDN Custom TimeSpan Format Strings page.

Here's an example timespan format string:

string.Format("{0:hh\\:mm\\:ss}", myTimeSpan); //example output 15:36:15

(UPDATE) and here is an example using C# 6 string interpolation:

$"{myTimeSpan:hh\\:mm\\:ss}"; //example output 15:36:15

You need to escape the ":" character with a "" (which itself must be escaped unless you're using a verbatim string).

This excerpt from the MSDN Custom TimeSpan Format Strings page explains about escaping the ":" and "." characters in a format string:

>The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example, "dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes.

Solution 2 - C#

For .NET 3.5 and lower you could use:

string.Format ("{0:00}:{1:00}:{2:00}", 
               (int)myTimeSpan.TotalHours, 
                    myTimeSpan.Minutes, 
                    myTimeSpan.Seconds);

Code taken from a Jon Skeet answer on bytes

For .NET 4.0 and above, see DoctaJonez answer.

Solution 3 - C#

One way is to create a DateTime object and use it for formatting:

new DateTime(myTimeSpan.Ticks).ToString(myCustomFormat)

// or using String.Format:
String.Format("{0:HHmmss}", new DateTime(myTimeSpan.Ticks))

This is the way I know. I hope someone can suggest a better way.

Solution 4 - C#

Simple. Use TimeSpan.ToString with c, g or G. More information at MSDN

Solution 5 - C#

I would go with

myTimeSpan.ToString("hh\\:mm\\:ss");

Solution 6 - C#

Dim duration As New TimeSpan(1, 12, 23, 62)

DEBUG.WriteLine("Time of Travel: " + duration.ToString("dd\.hh\:mm\:ss"))

It works for Framework 4

http://msdn.microsoft.com/en-us/library/ee372287.aspx

Solution 7 - C#

Personally, I like this approach:

TimeSpan ts = ...;
string.Format("{0:%d}d {0:%h}h {0:%m}m {0:%s}s", ts);

You can make this as custom as you like with no problems:

string.Format("{0:%d}days {0:%h}hours {0:%m}min {0:%s}sec", ts);
string.Format("{0:%d}d {0:%h}h {0:%m}' {0:%s}''", ts);

Solution 8 - C#

This is awesome one:

string.Format("{0:00}:{1:00}:{2:00}",
               (int)myTimeSpan.TotalHours,
               myTimeSpan.Minutes,
               myTimeSpan.Seconds);

Solution 9 - C#

You can also go with:

Dim ts As New TimeSpan(35, 21, 59, 59)  '(11, 22, 30, 30)    '
Dim TimeStr1 As String = String.Format("{0:c}", ts)
Dim TimeStr2 As String = New Date(ts.Ticks).ToString("dd.HH:mm:ss")

EDIT:

You can also look at Strings.Format.

    Dim ts As New TimeSpan(23, 30, 59)
    Dim str As String = Strings.Format(New DateTime(ts.Ticks), "H:mm:ss")

Solution 10 - C#

if (timeSpan.TotalDays < 1)
    return timeSpan.ToString(@"hh\:mm\:ss");

return timeSpan.TotalDays < 2
    ? timeSpan.ToString(@"d\ \d\a\y\ hh\:mm\:ss")
    : timeSpan.ToString(@"d\ \d\a\y\s\ hh\:mm\:ss");

All literal characters must be escaped.

Solution 11 - C#

This is the approach I used my self with conditional formatting. and I post it here because I think this is clean way.

$"{time.Days:#0:;;\\}{time.Hours:#0:;;\\}{time.Minutes:00:}{time.Seconds:00}"

example of outputs:

>00:00 (minimum) > > 1:43:04 (when we have hours) > > 15:03:01 (when hours are more than 1 digit) > > 2:4:22:04 (when we have days.)

The formatting is easy. time.Days:#0:;;\\ the format before ;; is for when value is positive. negative values are ignored. and for zero values we have;;\\ in order to hide it in formatted string. note that the escaped backslash is necessary otherwise it will not format correctly.

Solution 12 - C#

Here is my extension method:

public static string ToFormattedString(this TimeSpan ts)
{
    const string separator = ", ";

    if (ts.TotalMilliseconds < 1) { return "No time"; }

    return string.Join(separator, new string[]
    {
        ts.Days > 0 ? ts.Days + (ts.Days > 1 ? " days" : " day") : null,
        ts.Hours > 0 ? ts.Hours + (ts.Hours > 1 ? " hours" : " hour") : null,
        ts.Minutes > 0 ? ts.Minutes + (ts.Minutes > 1 ? " minutes" : " minute") : null,
        ts.Seconds > 0 ? ts.Seconds + (ts.Seconds > 1 ? " seconds" : " second") : null,
        ts.Milliseconds > 0 ? ts.Milliseconds + (ts.Milliseconds > 1 ? " milliseconds" : " millisecond") : null,
    }.Where(t => t != null));
}

Example call:

string time = new TimeSpan(3, 14, 15, 0, 65).ToFormattedString();

Output:

3 days, 14 hours, 15 minutes, 65 milliseconds

Solution 13 - C#

I used the code below. It is long, but still it is one expression, and produces very friendly output, as it does not outputs days, hours, minutes, or seconds if they have value of zero.

In the sample it produces output: "4 days 1 hour 3 seconds".

TimeSpan sp = new TimeSpan(4,1,0,3);
string.Format("{0}{1}{2}{3}", 
	    sp.Days > 0 ? ( sp.Days > 1 ? sp.ToString(@"d\ \d\a\y\s\ "): sp.ToString(@"d\ \d\a\y\ ")):string.Empty,
	    sp.Hours > 0 ? (sp.Hours > 1 ? sp.ToString(@"h\ \h\o\u\r\s\ ") : sp.ToString(@"h\ \h\o\u\r\ ")):string.Empty,
	    sp.Minutes > 0 ? (sp.Minutes > 1 ? sp.ToString(@"m\ \m\i\n\u\t\e\s\ ") :sp.ToString(@"m\ \m\i\n\u\t\e\ ")):string.Empty,
	    sp.Seconds > 0 ? (sp.Seconds > 1 ? sp.ToString(@"s\ \s\e\c\o\n\d\s"): sp.ToString(@"s\ \s\e\c\o\n\d\s")):string.Empty);

Solution 14 - C#

I use this method. I'm Belgian and speak dutch so plural of hours and minutes is not just adding 's' to the end but almost a different word than singular.

It may seem long but it is very readable I think:

 public static string SpanToReadableTime(TimeSpan span)
    {
        string[] values = new string[4];  //4 slots: days, hours, minutes, seconds
        StringBuilder readableTime = new StringBuilder();

        if (span.Days > 0)
        {
            if (span.Days == 1)
                values[0] = span.Days.ToString() + " dag"; //day
            else
                values[0] = span.Days.ToString() + " dagen";  //days

            readableTime.Append(values[0]);
            readableTime.Append(", ");
        }
        else
            values[0] = String.Empty;


        if (span.Hours > 0)
        {
            if (span.Hours == 1)
                values[1] = span.Hours.ToString() + " uur";  //hour
            else
                values[1] = span.Hours.ToString() + " uren";  //hours

            readableTime.Append(values[1]);
            readableTime.Append(", ");

        }
        else
            values[1] = string.Empty;

        if (span.Minutes > 0)
        {
            if (span.Minutes == 1)
                values[2] = span.Minutes.ToString() + " minuut";  //minute
            else
                values[2] = span.Minutes.ToString() + " minuten";  //minutes

            readableTime.Append(values[2]);
            readableTime.Append(", ");
        }
        else
            values[2] = string.Empty;

        if (span.Seconds > 0)
        {
            if (span.Seconds == 1)
                values[3] = span.Seconds.ToString() + " seconde";  //second
            else
                values[3] = span.Seconds.ToString() + " seconden";  //seconds

            readableTime.Append(values[3]);
        }
        else
            values[3] = string.Empty;


        return readableTime.ToString();
    }//end SpanToReadableTime

Solution 15 - C#

This is a pain in VS 2010, here's my workaround solution.

 public string DurationString
        {
            get 
            {
                if (this.Duration.TotalHours < 24)
                    return new DateTime(this.Duration.Ticks).ToString("HH:mm");
                else //If duration is more than 24 hours
                {
                    double totalminutes = this.Duration.TotalMinutes;
                    double hours = totalminutes / 60;
                    double minutes = this.Duration.TotalMinutes - (Math.Floor(hours) * 60);
                    string result = string.Format("{0}:{1}", Math.Floor(hours).ToString("00"), Math.Floor(minutes).ToString("00"));
                    return result;
                }
            } 
        }

Solution 16 - C#

The Substring method works perfectly when you only want the Hours:Minutes:Seconds. It's simple, clean code and easy to understand.

	var yourTimeSpan = DateTime.Now - DateTime.Now.AddMinutes(-2);

	var formatted = yourTimeSpan.ToString().Substring(0,8);// 00:00:00 

	Console.WriteLine(formatted);

Solution 17 - C#

No one has shown approach with decimal format specifier which is my favorite one, especially when used with string interpolation - https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#decimal-format-specifier-d

For example:

$"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2}.{time.Milliseconds:D3}"
// Sample output: 00:00:09.200

You can of course wrap it up in some helper method.

Solution 18 - C#

Here is my version. It shows only as much as necessary, handles pluralization, negatives, and I tried to make it lightweight.

Output Examples
0 seconds
1.404 seconds
1 hour, 14.4 seconds
14 hours, 57 minutes, 22.473 seconds
1 day, 14 hours, 57 minutes, 22.475 seconds
Code
public static class TimeSpanExtensions
{
	public static string ToReadableString(this TimeSpan timeSpan)
	{
		int days = (int)(timeSpan.Ticks / TimeSpan.TicksPerDay);
		long subDayTicks = timeSpan.Ticks % TimeSpan.TicksPerDay;

		bool isNegative = false;
		if (timeSpan.Ticks < 0L)
		{
			isNegative = true;
			days = -days;
			subDayTicks = -subDayTicks;
		}

		int hours = (int)((subDayTicks / TimeSpan.TicksPerHour) % 24L);
		int minutes = (int)((subDayTicks / TimeSpan.TicksPerMinute) % 60L);
		int seconds = (int)((subDayTicks / TimeSpan.TicksPerSecond) % 60L);
		int subSecondTicks = (int)(subDayTicks % TimeSpan.TicksPerSecond);
		double fractionalSeconds = (double)subSecondTicks / TimeSpan.TicksPerSecond;

		var parts = new List<string>(4);

		if (days > 0)
			parts.Add(string.Format("{0} day{1}", days, days == 1 ? null : "s"));
		if (hours > 0)
			parts.Add(string.Format("{0} hour{1}", hours, hours == 1 ? null : "s"));
		if (minutes > 0)
			parts.Add(string.Format("{0} minute{1}", minutes, minutes == 1 ? null : "s"));
		if (fractionalSeconds.Equals(0D))
		{
			switch (seconds)
			{
				case 0:
					// Only write "0 seconds" if we haven't written anything at all.
					if (parts.Count == 0)
						parts.Add("0 seconds");
					break;

				case 1:
					parts.Add("1 second");
					break;

				default:
					parts.Add(seconds + " seconds");
					break;
			}
		}
		else
		{
			parts.Add(string.Format("{0}{1:.###} seconds", seconds, fractionalSeconds));
		}

		string resultString = string.Join(", ", parts);
		return isNegative ? "(negative) " + resultString : resultString;
	}
}

Solution 19 - C#

If you want the duration format similar to youtube, given the number of seconds

int[] duration = { 0, 4, 40, 59, 60, 61, 400, 4000, 40000, 400000 };
foreach (int d in duration)
{
    Console.WriteLine("{0, 6} -> {1, 10}", d, d > 59 ? TimeSpan.FromSeconds(d).ToString().TrimStart("00:".ToCharArray()) : string.Format("0:{0:00}", d));
}

Output:

     0 ->       0:00
     4 ->       0:04
    40 ->       0:40
    59 ->       0:59
    60 ->       1:00
    61 ->       1:01
   400 ->       6:40
  4000 ->    1:06:40
 40000 ->   11:06:40
400000 -> 4.15:06:40

Solution 20 - C#

I wanted to return a string such as "1 day 2 hours 3 minutes" and also take into account if for example days or minuttes are 0 and then not showing them. thanks to John Rasch for his answer which mine is barely an extension of

TimeSpan timeLeft = New Timespan(0, 70, 0);
String.Format("{0}{1}{2}{3}{4}{5}",
    Math.Floor(timeLeft.TotalDays) == 0 ? "" : 
    Math.Floor(timeLeft.TotalDays).ToString() + " ",
    Math.Floor(timeLeft.TotalDays) == 0 ? "" : Math.Floor(timeLeft.TotalDays) == 1 ? "day " : "days ",
    timeLeft.Hours == 0 ? "" : timeLeft.Hours.ToString() + " ",
    timeLeft.Hours == 0 ? "" : timeLeft.Hours == 1 ? "hour " : "hours ",
    timeLeft.Minutes == 0 ? "" : timeLeft.Minutes.ToString() + " ",
    timeLeft.Minutes == 0 ? "" : timeLeft.Minutes == 1 ? "minute " : "minutes ");

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHosam AlyView Question on Stackoverflow
Solution 1 - C#Doctor JonesView Answer on Stackoverflow
Solution 2 - C#JohannesHView Answer on Stackoverflow
Solution 3 - C#Hosam AlyView Answer on Stackoverflow
Solution 4 - C#KKKView Answer on Stackoverflow
Solution 5 - C#Shehab FawzyView Answer on Stackoverflow
Solution 6 - C#Enel AlmonteView Answer on Stackoverflow
Solution 7 - C#NoOneView Answer on Stackoverflow
Solution 8 - C#HarpalView Answer on Stackoverflow
Solution 9 - C#NeverHopelessView Answer on Stackoverflow
Solution 10 - C#Ryan WilliamsView Answer on Stackoverflow
Solution 11 - C#M.kazem AkhgaryView Answer on Stackoverflow
Solution 12 - C#chviLadislavView Answer on Stackoverflow
Solution 13 - C#panpawelView Answer on Stackoverflow
Solution 14 - C#DabrielView Answer on Stackoverflow
Solution 15 - C#rguez06View Answer on Stackoverflow
Solution 16 - C#GERView Answer on Stackoverflow
Solution 17 - C#tometchyView Answer on Stackoverflow
Solution 18 - C#JHoView Answer on Stackoverflow
Solution 19 - C#zennyView Answer on Stackoverflow
Solution 20 - C#PieesView Answer on Stackoverflow