Come posso String.Format un oggetto TimeSpan con un formato personalizzato in .NET?


184

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

Risposte:


247

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 .

Le stringhe di formato TimeSpan personalizzate sono state introdotte in .Net 4.0. È possibile trovare un riferimento completo agli identificatori di formato disponibili nella pagina Stringhe di formato TimeSpan personalizzato MSDN .

Ecco un esempio di stringa in formato periodo:

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

( AGGIORNAMENTO ) ed ecco un esempio che utilizza l'interpolazione di stringhe C # 6:

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

Devi scappare dal carattere ":" con un "\" (che deve essere evitato a meno che tu non stia usando una stringa testuale).

Questo estratto dalla pagina Stringhe di formato TimeSpan personalizzato MSDN spiega come uscire da ":" e "." caratteri in una stringa di formato:

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


7
@Andrei Rinea: Corretto, come affermato all'inizio del mio secondo paragrafo ".Net 4 ti consente di utilizzare stringhe di formato personalizzate con Timespan".
Doctor Jones,

1
@Edward, non è del tutto esatto. Nel tuo esempio stai sfuggendo al primo me al primo s, quindi con un input myTimeSpan = new TimeSpan(15, 35, 54);dell'istruzione myTimeSpan .ToString("hh\\mm\\ss");risulterà 15m35s54. Non penso che sia quello che intendevi in ​​quanto posizionerà una m dopo le tue ore e una s dopo i tuoi minuti.
Doctor Jones,

1
@Doctor Jones - Grazie! Intendevo myTimeSpan.ToString ("h \\ hm \\ ms \\ s"); o myTimeSpan.ToString (@ "h \ hm \ ms \ s"); che dà 15h35m54s
Edward

2
stai

1
@QuarK, non esiste un identificatore di formato personalizzato che lo faccia, tutti ti danno le ore che non vengono conteggiate come parte dei giorni. Invece potresti farlo $"{myTimeSpan.TotalHours}:{myTimeSpan:mm\\:ss}". Dal punto di vista dell'utente, potrebbe essere meglio produrre i giorni, tuttavia nessuno vuole capire mentalmente quanti giorni sono in oltre 200 ore.
Dottore Jones,

91

Per .NET 3.5 e versioni precedenti è possibile utilizzare:

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

Codice ricavato da una risposta di Jon Skeet sui byte

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


Si Grazie. Ma penso che l'approccio DateTime sia più personalizzabile, poiché funzionerebbe per qualsiasi formato orario supportato da DateTime. Questo approccio è difficile da usare per mostrare AM / PM per esempio.
Hosam Aly,

1
Certo, TimeSpan è pensato per rappresentare un periodo di tempo, non un'ora del giorno (anche se la proprietà DateTime.Now.TimeOfDay vorrebbe farvi credere diversamente). Se devi rappresentare un'ora specifica del giorno, ti suggerisco di continuare a utilizzare la classe DateTime.
JohannesH,

7
Ricorda solo che se TimeSpan è uguale o superiore a 24 ore otterrai una formattazione errata.
JohannesH,

31

Un modo è creare un DateTimeoggetto 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.


14
Funzionerà davvero solo se TimeSpan è inferiore a un giorno. Potrebbe non essere una restrizione così terribile, ma le impedisce di essere una soluzione generale.
tvanfosson,

Restituisce il valore corretto? Dim ts As New TimeSpan (11, 22, 30, 30): Dim sss As String = New DateTime (ts.Ticks) .ToString ("dd.hh: mm: ss")
NeverHopeless

10

Semplice. Utilizzare TimeSpan.ToStringcon c, g o G. Ulteriori informazioni su MSDN


1
La ringrazio per la risposta. Questo metodo è apparentemente nuovo in .NET 4 e non esisteva al momento della domanda. Inoltre non supporta i formati personalizzati. Tuttavia, è una preziosa aggiunta alle risposte a queste domande. Grazie ancora.
Hosam Aly,

8

Vorrei andare con

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

Semplice e pulito! un'alternativa è @ "hh \: mm \: ss"
Xilmiki,


5

Personalmente, mi piace questo approccio:

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

Puoi renderlo personalizzato come preferisci 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);

5

Questo è fantastico:

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

1
Devi trasmettere myTimeSpan.TotalHours a un int, altrimenti potrebbe essere arrotondato per eccesso. Vedi la risposta di JohannesH
codeulike,

3

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

3
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.


1

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

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

Ora c'è un modo molto migliore per scrivere questo! Prova a riformattare tutte le operazioni comuni e puoi rendere questo codice molto, molto meglio.
Hosam Aly,

@Hosam Aly; Sto imparando tutto il tempo, ti interessa pubblicare il tuo codice migliorato?
Panpawel

String timeComponent(int value, String name) { return value > 0 ? value + " " + name + (value > 1 ? "s" : ""); }Chiamalo per ciascun componente (ad es. timeComponent(sp.Days, "day")), Quindi usa String.joinper inserire gli spazi.
Hosam Aly,

1

Uso questo metodo Sono belga e parlo olandese così plurale di ore e minuti non solo aggiungendo 's' alla fine ma quasi una parola diversa da 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

Se scrivi un software che deve essere tradotto, allora è praticamente la strada da percorrere. Il TimeSpan.ToString () standard è troppo ingombrante per essere compreso dai normali utenti finali, soprattutto quando l'intervallo è superiore a un giorno.
Neil,

1

Questo è l'approccio che ho usato da solo 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 output:

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 vengono ignorati. e per valori zero abbiamo ;;\\per nasconderlo nella stringa formattata. notare che la barra rovesciata di escape è necessaria altrimenti non verrà formattata correttamente.


1

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

Esempio di chiamata:

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

Produzione:

3 days, 14 hours, 15 minutes, 65 milliseconds

1

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

1

Il Substringmetodo funziona perfettamente quando vuoi solo le Ore: Minuti: Secondi. È un codice semplice, pulito e di facile comprensione.

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

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

    Console.WriteLine(formatted);

0

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

0

Se desideri un formato di durata simile a quello di 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

0

Volevo restituire una stringa come "1 giorno 2 ore 3 minuti" e anche prendere in considerazione se ad esempio giorni o minuti sono 0 e quindi non li mostrano. grazie a John Rasch per la sua risposta di cui la mia è a malapena un'estensione

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 ");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.