Como posso String.Formatar um object TimeSpan com um formato personalizado no .net?

Qual é a maneira recomendada de formatar objects TimeSpan em uma string com um formato personalizado?

Por favor note: esta resposta é para .net 4.0 e acima. Se você deseja formatar um TimeSpan no .Net 3.5 ou abaixo, por favor, veja a resposta de JohannesH .

Cadeias de formato TimeSpan personalizadas foram introduzidas no .Net 4.0. Você pode encontrar uma referência completa dos especificadores de formato disponíveis na página Strings de Formato TimeSpan do MSDN.

Aqui está um exemplo de string de formato de tempo:

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

( UPDATE ) e aqui está um exemplo usando a interpolação de string C # 6:

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

Você precisa escaping do caractere “:” com um “\” (que deve ser salvo a menos que você esteja usando uma string textual).

Este trecho da página Strings de Formato TimeSpan do MSDN explica como escaping do “:” e “.” caracteres em uma string de formato:

Os especificadores de formato TimeSpan personalizados não incluem símbolos separadores de espaços reservados, como os símbolos que separam dias de horas, horas de minutos ou segundos de segundos fracionários. Em vez disso, esses símbolos devem ser incluídos na string de formato personalizado como literais de string. Por exemplo, “dd.hh: mm” define um ponto (.) Como separador entre dias e horas e dois pontos (:) como separador entre horas e minutos.

Para o .NET 3.5 e inferior, você pode usar:

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

Código retirado de uma resposta do Jon Skeet em bytes

Para .NET 4.0 e superior, consulte a resposta do DoctaJonez.

Uma maneira é criar um object DateTime e usá-lo para formatação:

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

É assim que eu sei. Espero que alguém possa sugerir um caminho melhor.

Simples. Use TimeSpan.ToString com c, g ou G. Mais informações em http://msdn.microsoft.com/pt-br/library/ee372286.aspx

 Dim duration As New TimeSpan(1, 12, 23, 62) DEBUG.WriteLine("Time of Travel: " + duration.ToString("dd\.hh\:mm\:ss")) 

Funciona para o Framework 4

http://msdn.microsoft.com/pt-br/library/ee372287.aspx

Pessoalmente, gosto dessa abordagem:

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

Você pode fazer isso como personalizado, sem problemas:

 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); 

Eu iria com

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

Isso é incrível:

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

Você também pode ir com:

 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") 

EDITAR:

Você também pode olhar para Strings.Format .

  Dim ts As New TimeSpan(23, 30, 59) Dim str As String = Strings.Format(New DateTime(ts.Ticks), "H:mm:ss") 
 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"); 

Todos os caracteres literais devem ser escapados.

Eu usei o código abaixo. É longo, mas ainda assim é uma expressão e produz uma saída muito amigável, pois não gera dias, horas, minutos ou segundos se eles tiverem valor zero.

Na amostra, produz saída: “4 dias 1 hora 3 segundos”.

 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); 

Eu uso esse método. Eu sou belga e falo holandês, então o plural de horas e minutos não é apenas adicionar ‘s’ ao final, mas quase uma palavra diferente do singular.

Pode parecer longo, mas é muito legível, eu acho:

  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 

Isso é uma dor no VS 2010, aqui está minha solução alternativa.

  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; } } } 

Essa é a abordagem que usei com formatação condicional. e eu postei aqui porque acho que esse é um jeito limpo.

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

exemplo de saídas:

00:00 (mínimo)

1:43:04 (quando tivermos horas)

15:03:01 (quando as horas são mais de 1 dígito)

2:4:22:04 (quando temos dias)

A formatação é fácil. time.Days:#0:;;\\ o formato antes ;; é para quando o valor é positivo. valores negativos são ignorados. e para valores zero nós temos ;;\\ para escondê-lo em uma string formatada. observe que a barra invertida de escape é necessária, caso contrário, ela não será formatada corretamente.

Aqui está a minha versão. Ele mostra apenas o necessário, lida com pluralização, negativos e eu tentei torná-lo leve.

Exemplos de saída

 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 

Código

 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(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; } } 

Se você quiser o formato de duração semelhante ao youtube, dado o número de segundos

 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)); } 

Saída:

  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 

Eu queria retornar uma string como “1 dia 2 horas 3 minutos” e também levar em conta se, por exemplo, dias ou minuttes são 0 e, em seguida, não mostrá-los. graças a John Rasch por sua resposta que o meu é apenas uma extensão de

 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 "); 

Aqui está o meu método de extensão :

 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)); } 

Exemplo de chamada:

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

Saída:

 3 days, 14 hours, 15 minutes, 65 milliseconds