Come posso String.Formattare un object TimeSpan con un formato personalizzato in .NET?

Qual è il modo consigliato di formattare gli oggetti TimeSpan in una stringa con un formato personalizzato?

Nota: questa risposta è per .Net 4.0 e versioni successive. Se si desidera formattare un TimeSpan in .Net 3.5 o inferiore, consultare la risposta di JohannesH .

Sono state introdotte stringhe di formato TimeSpan personalizzate in .Net 4.0. È ansible trovare un riferimento completo degli specificatori di formato disponibili nella pagina Stringa di formato TimeSpan personalizzata di MSDN .

Ecco un esempio di stringa di formato temporale:

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

( AGGIORNAMENTO ) ed ecco un esempio usando l’interpolazione di stringa C # 6:

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

È necessario sfuggire al carattere “:” con una “\” (che deve essere sfuggita a meno che non si stia utilizzando una stringa letterale).

Questo estratto dalla pagina Stringhe di formato di TimeSpan personalizzate di MSDN spiega l’escape di “:” e “.” caratteri in una stringa di formato:

Gli identificatori di formato TimeSpan personalizzati non includono simboli separatori segnaposto, ad esempio i simboli che separano i giorni da ore, ore da minuti o secondi da secondi frazionari. Invece, questi simboli devono essere inclusi nella stringa di formato personalizzata come stringhe letterali. Ad esempio, “dd.hh: mm” definisce un punto (.) Come separatore tra giorni e ore e due punti (:) come separatore tra ore e minuti.

Per .NET 3.5 e versioni inferiori è ansible utilizzare:

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

Codice preso da una risposta di Jon Skeet su byte

Per .NET 4.0 e versioni successive, consultare la risposta di DoctaJonez.

Un modo è creare un object DateTime e usarlo per la formattazione:

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

Questo è il modo in cui lo so. Spero che qualcuno possa suggerire un modo migliore.

Semplice. Usa TimeSpan.ToString con c, g o G. Ulteriori informazioni su 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")) 

Funziona per Framework 4

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

Personalmente, mi piace questo approccio:

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

Puoi renderlo come di consueto senza problemi:

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

Vorrei andare con

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

Questo è fantastico:

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

Puoi anche andare 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") 

MODIFICARE:

Puoi anche guardare 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"); 

Tutti i personaggi letterali devono essere sfuggiti.

Ho usato il codice qui sotto. È lungo, ma è sempre un’espressione e produce un output molto amichevole, poiché non emette giorni, ore, minuti o secondi se hanno un valore pari a zero.

Nell’esempio produce output: “4 giorni 1 ora 3 secondi”.

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

Io uso questo metodo. Sono belga e parlo olandese così plurale di ore e minuti non è solo l’aggiunta di ‘s’ alla fine, ma quasi una parola diversa da quella singolare.

Può sembrare lungo ma è molto leggibile penso:

  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 

Questo è un dolore in VS 2010, ecco la mia soluzione 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; } } } 

Questo è l’approccio che ho usato io con la formattazione condizionale. e lo pubblico qui perché penso che sia pulito.

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

esempio di uscite:

00:00 (minimo)

1:43:04 (quando abbiamo ore)

15:03:01 (quando le ore sono più di 1 cifra)

2:4:22:04 (quando abbiamo giorni.)

La formattazione è semplice. time.Days:#0:;;\\ il formato precedente ;; è per quando il valore è positivo. i valori negativi sono ignorati. e per zero valori abbiamo ;;\\ per nasconderlo in una stringa formattata. nota che la backslash con escape è necessaria altrimenti non verrà formattata correttamente.

Ecco la mia versione. Mostra solo quanto necessario, gestisce la pluralizzazione, i negativi e ho cercato di renderlo leggero.

Esempi di output

 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 

Codice

 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 vuoi il formato della durata simile a YouTube, dato il numero di secondi

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

Produzione:

  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 

Volevo restituire una stringa come “1 giorno 2 ore 3 minuti” e tenere conto anche se per esempio giorni o minuti sono 0 e quindi non li mostra. grazie a John Rasch per la sua risposta che la mia è a malapena un’estensione di

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

Ecco il mio metodo di estensione :

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

Chiamata di esempio:

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

Produzione:

 3 days, 14 hours, 15 minutes, 65 milliseconds