Wie kann ich ein TimeSpan-Objekt mit einem benutzerdefinierten Format in .NET string.Formatieren?

184

Was ist die empfohlene Methode zum Formatieren von TimeSpanObjekten in eine Zeichenfolge mit einem benutzerdefinierten Format?

Hosam Aly
quelle

Antworten:

246

Bitte beachten Sie: Diese Antwort gilt für .Net 4.0 und höher. Wenn Sie eine Zeitspanne in .Net 3.5 oder niedriger formatieren möchten, lesen Sie bitte die Antwort von JohannesH .

In .Net 4.0 wurden benutzerdefinierte Zeichenfolgen im TimeSpan-Format eingeführt. Eine vollständige Referenz der verfügbaren Formatspezifizierer finden Sie auf der Seite MSDN Custom TimeSpan Format Strings .

Hier ist ein Beispiel für eine Zeichenfolge im Zeitspannenformat:

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

( UPDATE ) und hier ein Beispiel mit C # 6-String-Interpolation:

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

Sie müssen das Zeichen ":" mit einem "\" maskieren (das selbst maskiert werden muss, es sei denn, Sie verwenden eine wörtliche Zeichenfolge).

In diesem Auszug aus der Seite MSDN Custom TimeSpan Format Strings wird erläutert, wie Sie das ":" und "." Zeichen in einer Formatzeichenfolge:

Die benutzerdefinierten TimeSpan-Formatspezifizierer enthalten keine Platzhaltertrennzeichen, z. B. Symbole, die Tage von Stunden, Stunden von Minuten oder Sekunden von Bruchsekunden trennen. Stattdessen müssen diese Symbole als Zeichenfolgenliterale in die Zeichenfolge im benutzerdefinierten Format aufgenommen werden. Beispielsweise definiert "dd.hh: mm" einen Punkt (.) Als Trennzeichen zwischen Tagen und Stunden und einen Doppelpunkt (:) als Trennzeichen zwischen Stunden und Minuten.

Doktor Jones
quelle
7
@Andrei Rinea: Richtig, wie am Anfang meines zweiten Absatzes angegeben. ".Net 4 ermöglicht es Ihnen, benutzerdefinierte Formatzeichenfolgen mit Timespan zu verwenden".
Doktor Jones
1
@ Edward, das ist nicht ganz richtig. In Ihrem Beispiel entkommen Sie dem ersten m und dem ersten s, sodass eine Eingabe myTimeSpan = new TimeSpan(15, 35, 54);der Anweisung myTimeSpan .ToString("hh\\mm\\ss");dazu führt 15m35s54. Ich glaube nicht, dass Sie das beabsichtigt haben, da es ein m nach Ihren Stunden und ein s nach Ihren Minuten platzieren wird.
Doktor Jones
1
@ Doctor Jones - Danke! Ich meinte myTimeSpan.ToString ("h \\ hm \\ ms \\ s"); oder myTimeSpan.ToString (@ "h \ hm \ ms \ s"); das gibt 15h35m54s
Edward
2
Seien
1
@QuarK, es gibt keinen benutzerdefinierten Formatbezeichner, der dies tut. Alle geben Ihnen die Stunden an, die nicht als Teil der Tage gezählt werden. Sie könnten dies stattdessen tun $"{myTimeSpan.TotalHours}:{myTimeSpan:mm\\:ss}". Aus Anwendersicht ist es möglicherweise besser, die Tage auszugeben, aber niemand möchte mental herausfinden, wie viele Tage in mehr als 200 Stunden liegen.
Doktor Jones
91

Für .NET 3.5 und niedriger können Sie Folgendes verwenden:

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

Code aus einer Jon Skeet- Antwort auf Bytes

Informationen zu .NET 4.0 und höher finden Sie unter DoctaJonez- Antwort .

JohannesH
quelle
Ja Dankeschön. Ich denke jedoch, dass der DateTime-Ansatz anpassbarer ist, da er für jedes von DateTime unterstützte Zeitformat funktioniert. Dieser Ansatz ist beispielsweise zum Anzeigen von AM / PM schwer zu verwenden.
Hosam Aly
1
Sicher, TimeSpan soll einen Zeitraum darstellen, keine Tageszeit (auch wenn Sie mit der DateTime.Now.TimeOfDay-Eigenschaft etwas anderes glauben würden). Wenn Sie eine bestimmte Tageszeit darstellen müssen, empfehlen wir Ihnen, die DateTime-Klasse weiterhin zu verwenden.
JohannesH
7
Denken Sie daran, dass bei einer Zeitspanne von mindestens 24 Stunden eine falsche Formatierung auftritt.
JohannesH
31

Eine Möglichkeit besteht darin, ein DateTimeObjekt zu erstellen und es zum Formatieren zu verwenden:

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

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

So weiß ich es. Ich hoffe, jemand kann einen besseren Weg vorschlagen.

Hosam Aly
quelle
14
Dies wird wirklich nur funktionieren, wenn die Zeitspanne weniger als einen Tag beträgt. Das ist vielleicht keine so schreckliche Einschränkung, aber es verhindert, dass es eine allgemeine Lösung ist.
Tvanfosson
Gibt es den korrekten Wert zurück? Dim ts As New TimeSpan (11, 22, 30, 30): Dim sss As String = Neue DateTime (ts.Ticks) .ToString ("dd.hh: mm: ss")
NeverHopeless
10

Einfach. Verwendung TimeSpan.ToStringmit c, g oder G. Weitere Informationen unter MSDN

KKK
quelle
1
Vielen Dank für Ihre Antwort. Diese Methode ist anscheinend neu in .NET 4 und existierte nicht, als die Frage gestellt wurde. Benutzerdefinierte Formate werden ebenfalls nicht unterstützt. Trotzdem ist es eine wertvolle Ergänzung zu den Antworten auf diese Fragen. Danke noch einmal.
Hosam Aly
8

Ich würde mit gehen

myTimeSpan.ToString("hh\\:mm\\:ss");
Shehab Fawzy
quelle
Einfach und sauber! Eine Alternative ist @ "hh \: mm \: ss"
Xilmiki
5

Persönlich mag ich diesen Ansatz:

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

Sie können dies ohne Probleme so individuell gestalten, wie Sie möchten:

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);
Niemand
quelle
5

Das ist großartig:

string.Format("{0:00}:{1:00}:{2:00}",
               (int)myTimeSpan.TotalHours,
               myTimeSpan.Minutes,
               myTimeSpan.Seconds);
Harpal
quelle
1
Sie müssen myTimeSpan.TotalHours in ein int umwandeln - andernfalls wird es möglicherweise aufgerundet. Siehe JohannesHs Antwort
codeulike
3

Sie können auch gehen mit:

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

BEARBEITEN:

Sie können sich auch Strings.Format ansehen .

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

Alle Literalzeichen müssen maskiert werden.

Ryan Williams
quelle
1

Ich habe den folgenden Code verwendet. Es ist lang, aber dennoch ein Ausdruck und erzeugt eine sehr freundliche Ausgabe, da es keine Tage, Stunden, Minuten oder Sekunden ausgibt, wenn sie den Wert Null haben.

In der Probe wird die Ausgabe "4 Tage 1 Stunde 3 Sekunden" erzeugt.

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);
Panpawel
quelle
Jetzt gibt es einen viel besseren Weg, dies zu schreiben! Versuchen Sie, alle gängigen Vorgänge umzugestalten, und Sie können diesen Code viel, viel besser aussehen lassen.
Hosam Aly
@ Hosam Aly; Ich lerne die ganze Zeit. Möchtest du deinen verbesserten Code veröffentlichen?
Panpawel
String timeComponent(int value, String name) { return value > 0 ? value + " " + name + (value > 1 ? "s" : ""); }Nennen Sie das für jede Komponente (z. B. timeComponent(sp.Days, "day")) und String.joinfügen Sie dann die Leerzeichen ein.
Hosam Aly
1

Ich benutze diese Methode. Ich bin Belgier und spreche Niederländisch, so dass mehrere Stunden und Minuten nicht nur 's' am Ende hinzufügen, sondern fast ein anderes Wort als Singular.

Es mag lang erscheinen, ist aber meiner Meinung nach sehr gut lesbar:

 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
Dabriel
quelle
Wenn Sie Software schreiben, die übersetzt werden muss, ist dies so ziemlich der richtige Weg. Das Standard-TimeSpan.ToString () ist für normale Endbenutzer einfach zu klobig, um es zu verstehen, insbesondere wenn die Zeitspanne mehr als einen Tag beträgt.
Neil
1

Dies ist der Ansatz, den ich selbst bei der bedingten Formatierung verwendet habe. und ich poste es hier, weil ich denke, dass dies ein sauberer Weg ist.

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

Beispiel für Ausgänge:

00:00 (Minimum)

1:43:04 (wenn wir Stunden haben)

15:03:01 (wenn die Stunden mehr als eine Ziffer sind)

2:4:22:04 (Wenn wir Tage haben.)

Die Formatierung ist einfach. time.Days:#0:;;\\Das vorherige Format ;;ist für den Fall, dass der Wert positiv ist. negative Werte werden ignoriert. und für Nullwerte haben wir ;;\\, um es in formatierten Zeichenfolgen zu verbergen. Beachten Sie, dass der maskierte Backslash erforderlich ist, da er sonst nicht korrekt formatiert wird.

M. kazem Akhgary
quelle
1

Hier ist meine Erweiterungsmethode :

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

Beispielaufruf:

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

Ausgabe:

3 days, 14 hours, 15 minutes, 65 milliseconds
chviLadislav
quelle
1

Dies ist ein Problem in VS 2010, hier ist meine Problemumgehungslösung.

 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;
                }
            } 
        }
rguez06
quelle
1

Die SubstringMethode funktioniert perfekt, wenn Sie nur die Stunden: Minuten: Sekunden möchten. Es ist einfacher, sauberer Code und leicht zu verstehen.

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

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

    Console.WriteLine(formatted);
GER
quelle
0

Hier ist meine Version. Es zeigt nur so viel wie nötig, behandelt Pluralisierung, Negative und ich habe versucht, es leicht zu machen.

Ausgabebeispiele

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;
    }
}
JHo
quelle
0

Wenn Sie das Dauerformat ähnlich wie bei YouTube möchten, geben Sie die Anzahl der Sekunden an

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

Ausgabe:

     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
Zenny
quelle
0

Ich wollte eine Zeichenfolge wie "1 Tag 2 Stunden 3 Minuten" zurückgeben und auch berücksichtigen, ob beispielsweise Tage oder Minuten 0 sind und sie dann nicht anzeigen. Vielen Dank an John Rasch für seine Antwort, von der meine kaum eine Erweiterung ist

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 ");
Stücke
quelle