我如何在.NET中使用自定义格式String.Format一个TimeSpan对象?

How can I String.Format a TimeSpan object with a custom format in .NET?

使用自定义格式将TimeSpan对象格式化为字符串的建议方法是什么?


请注意:此答案适用于.NET 4.0及更高版本。如果您想在.NET 3.5或更低版本中格式化时间跨度,请参阅Johannesh的答案。

在.NET 4.0中引入了自定义TimeSpan格式字符串。您可以在"msdn自定义时间跨度格式字符串"页上找到可用格式说明符的完整引用。

以下是TimeSpan格式字符串示例:

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

(更新)下面是一个使用C 6字符串插值的示例:

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

您需要转义":"字符和""(除非使用逐字字符串,否则必须转义该字符本身)。

此摘录来自"msdn自定义TimeSpan格式字符串"页,介绍如何转义格式字符串中的":"和"."字符:

The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example,"dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes.


对于.NET 3.5及更低版本,您可以使用:

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

从jon-skeet字节应答中提取的代码

有关.NET 4.0及更高版本,请参阅doctajonez answer。


一种方法是创建DateTime对象并将其用于格式化:

1
2
3
4
new DateTime(myTimeSpan.Ticks).ToString(myCustomFormat)

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

我就是这样知道的。我希望有人能提出更好的办法。


简单。将TimeSpan.ToString与c、g或g一起使用。有关详细信息,请访问msdn。


我会和你一起去的

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


1
2
3
Dim duration As New TimeSpan(1, 12, 23, 62)

DEBUG.WriteLine("Time of Travel:" + duration.ToString("dd\.hh\:mm\:ss"))

它适用于框架4

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


这真是太棒了:

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


就我个人而言,我喜欢这种方法:

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

您可以根据自己的喜好进行定制,不会出现任何问题:

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

您也可以选择:

1
2
3
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")

编辑:

您还可以查看strings.format。

1
2
    Dim ts As New TimeSpan(23, 30, 59)
    Dim str As String = Strings.Format(New DateTime(ts.Ticks),"H:mm:ss")

1
2
3
4
5
6
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");

必须转义所有文字字符。


我用这个方法。我是比利时人,会说荷兰语,所以小时和分钟的复数形式不仅仅是在结尾加上"s",而且几乎和单数形式不同。

它可能看起来很长,但我认为它可读性很强:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 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


这是我的扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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));
}

示例调用:

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

输出:

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


这是与2010年相比的痛苦,这是我的解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 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;
                }
            }
        }


我用了下面的代码。它很长,但仍然是一个表达式,并且产生非常友好的输出,因为它不输出天、小时、分钟或秒(如果它们的值为零)。

在样本中,它产生输出:"4天1小时3秒"。

1
2
3
4
5
6
7
8
9
10
11
12
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
\s") : sp.ToString(@"h\ \h\o\u
")):string.Empty,
        sp.Minutes > 0 ? (sp.Minutes > 1 ? sp.ToString(@"m\ \m\i
\u\t\e\s") :sp.ToString(@"m\ \m\i
\u\t\e")):string.Empty,
        sp.Seconds > 0 ? (sp.Seconds > 1 ? sp.ToString(@"s\ \s\e\c\o
\d\s"): sp.ToString(@"s\ \s\e\c\o
\d\s")):string.Empty);


当您只需要小时:分钟:秒时,Substring方法工作得很好。它简单、代码清晰、易于理解。

1
2
3
4
5
    var yourTimeSpan = DateTime.Now - DateTime.Now.AddMinutes(-2);

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

    Console.WriteLine(formatted);

这是我使用自己的条件格式的方法。我把它贴在这里,因为我认为这是干净的方式。

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

输出示例:

00:00 (minimum)

1:43:04 (when we have hours)

15:03:01 (when hours are more than 1 digit)

2:4:22:04 (when we have days.)

格式化很容易。time.Days:#0:;;\\值为正数时,;;前的格式为。忽略负值。对于零值,我们使用了cx1(4),以便将其隐藏在格式化字符串中。请注意,转义反斜杠是必需的,否则它将无法正确格式化。


这是我的版本。它只显示了尽可能多的必要性,处理了复数和否定,我试图使它轻量级。

输出示例

1
2
3
4
5
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

号代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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;
    }
}


如果您想要类似于YouTube的持续时间格式,给定秒数

1
2
3
4
5
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));
}

输出:

1
2
3
4
5
6
7
8
9
10
     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


我想返回一个字符串,例如"1天2小时3分钟",并且还考虑到例如,天或分钟是0,然后不显示它们。多亏了约翰·拉希的回答,我的回答只是

1
2
3
4
5
6
7
8
9
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");