¿Cómo puedo String.Format un objeto TimeSpan con un formato personalizado en .NET?

¿Cuál es la forma recomendada de formatear objetos TimeSpan en una cadena con un formato personalizado?

Tenga en cuenta: esta respuesta es para .Net 4.0 y superior. Si desea formatear un TimeSpan en .Net 3.5 o inferior, consulte la respuesta de JohannesH .

Las cadenas de formato TimeSpan personalizadas se introdujeron en .Net 4.0. Puede encontrar una referencia completa de los especificadores de formato disponibles en la página Cadenas de formato de TimeSpan personalizado de MSDN.

Aquí hay un ejemplo de cadena de formato de intervalo de tiempo:

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

( ACTUALIZACIÓN ) y aquí hay un ejemplo usando la interpolación de cadenas C # 6:

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

Necesita escapar del carácter “:” con una “\” (que a su vez debe escaparse a menos que esté usando una cadena literal).

Este extracto de la página de cadenas de formato de TimeSpan personalizado de MSDN explica cómo evitar “:” y “.” Caracteres en una cadena de formato:

Los especificadores de formato TimeSpan personalizados no incluyen símbolos separadores de marcador de posición, como los símbolos que separan días de horas, horas de minutos o segundos de segundos fraccionarios. En cambio, estos símbolos se deben incluir en la cadena de formato personalizado como literales de cadena. Por ejemplo, “dd.hh: mm” define un período (.) Como el separador entre días y horas, y dos puntos (:) como el separador entre horas y minutos.

Para .NET 3.5 y versiones anteriores, puede usar:

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

Código tomado de una respuesta de Jon Skeet en bytes

Para .NET 4.0 y superior, consulte la respuesta de DoctaJonez.

Una forma es crear un objeto DateTime y usarlo para formatear:

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

Esta es la forma en que sé. Espero que alguien pueda sugerir una mejor manera.

Sencillo. Utilice TimeSpan.ToString con c, go G. Obtenga más información en http://msdn.microsoft.com/en-us/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 el Marco 4

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

Personalmente, me gusta este enfoque:

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

Puede hacer esto tan personalizado como desee sin 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); 

Yo iría con

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

Esto es asombroso:

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

También puedes ir con:

 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:

También puedes mirar 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 los caracteres literales deben ser escapados.

Usé el código a continuación. Es largo, pero sigue siendo una expresión y produce resultados muy amigables, ya que no genera días, horas, minutos o segundos si tienen valor de cero.

En la muestra produce salida: “4 días, 1 hora y 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); 

Yo uso este método Soy belga y hablo holandés, así que el plural de horas y minutos no es solo agregar ‘s’ al final, sino casi una palabra diferente de singular.

Puede parecer largo, pero es muy legible, creo:

  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 

Esto es un dolor en VS 2010, aquí está mi solución 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; } } } 

Este es el enfoque que usé yo mismo con el formato condicional. y lo publico aquí porque creo que esta es una manera limpia.

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

ejemplo de resultados:

00:00 (mínimo)

1:43:04 (cuando tenemos horas)

15:03:01 (cuando las horas son más de 1 dígito)

2:4:22:04 (cuando tenemos días).

El formateo es fácil. time.Days:#0:;;\\ el formato anterior ;; es para cuando el valor es positivo. los valores negativos son ignorados y para los valores cero tenemos ;;\\ para ocultarlo en una cadena formateada. Tenga en cuenta que la barra invertida escapada es necesaria, de lo contrario no formateará correctamente.

Aquí está mi versión. Muestra solo todo lo que sea necesario, maneja la pluralización, los negativos, y traté de hacerlo liviano.

Ejemplos de salida

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

Si desea el formato de duración similar a youtube, dada la cantidad 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)); } 

Salida:

  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 

Quería devolver una cadena como “1 día, 2 horas y 3 minutos” y también tener en cuenta si, por ejemplo, los días o minutos son 0 y luego no se muestran. gracias a John Rasch por su respuesta, que el mío es apenas una extensión 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 "); 

Aquí está mi método de extensión :

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

Ejemplo de llamada:

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

Salida:

 3 days, 14 hours, 15 minutes, 65 milliseconds