Как я могу String.Format объект TimeSpan с пользовательским форматом в .NET?


Ответы:


247

Обратите внимание: этот ответ предназначен для .Net 4.0 и выше. Если вы хотите отформатировать TimeSpan в .Net 3.5 или ниже, пожалуйста, смотрите ответ JohannesH .

Пользовательские строки формата TimeSpan были введены в .Net 4.0. Вы можете найти полную ссылку на доступные спецификаторы формата на странице строк формата MSDN Custom TimeSpan .

Вот пример строки формата временного интервала:

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

( ОБНОВЛЕНИЕ ) и вот пример, использующий интерполяцию строки C # 6:

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

Вы должны экранировать символ «:» с помощью символа «\» (который сам должен быть экранирован, если вы не используете дословную строку).

В этом отрывке со страницы строк формата MSDN Custom TimeSpan объясняется экранирование символов «:» и «.» символы в строке формата:

Пользовательские спецификаторы формата TimeSpan не включают символы-разделители-заполнители, такие как символы, которые отделяют дни от часов, часы от минут или секунды от дробных секунд. Вместо этого эти символы должны быть включены в строку пользовательского формата в виде строковых литералов. Например, «dd.hh: mm» определяет точку (.) Как разделитель между днями и часами, а двоеточие (:) - как разделитель между часами и минутами.


7
@ Андрей Ринеа: Исправьте, как указано в начале моего второго абзаца «.Net 4 позволяет вам использовать строки произвольного формата с Timespan».
Доктор Джонс

1
@ Эдвард, это не совсем верно. В вашем примере вы экранируете первые m и первые s, поэтому при вводе myTimeSpan = new TimeSpan(15, 35, 54);оператора вы myTimeSpan .ToString("hh\\mm\\ss");получите 15m35s54. Я не думаю, что это то, что вы намеревались, так как это будет M после ваших часов и S после ваших минут.
Доктор Джонс

1
@ Доктор Джонс - Спасибо! Я имел в виду myTimeSpan.ToString ("h \\ hm \\ ms \\ s"); или myTimeSpan.ToString (@ "h \ hm \ ms \ s"); что дает 15х35м54с
Эдвард

2
просто будьте осторожны с этим решением, потому что оно не будет работать правильно, когда часть Часов больше 24
Золтан Тиринда

1
@QuarK, нет никакого специального спецификатора формата, который делает это, они все дают вам часы, которые не учитываются как часть дней. Вы могли бы сделать это вместо этого, хотя $"{myTimeSpan.TotalHours}:{myTimeSpan:mm\\:ss}". С точки зрения пользователя, было бы лучше вывести дни, хотя никто не хочет мысленно выяснить, сколько дней в 200+ часов.
Доктор Джонс

91

Для .NET 3.5 и ниже вы можете использовать:

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

Код взят из ответа Джона Скита на байты

Для .NET 4.0 и выше, см. Ответ DoctaJonez .


Да спасибо. Но я думаю, что подход DateTime более настраиваемый, так как он будет работать для любого формата времени, поддерживаемого DateTime. Этот подход трудно использовать, например, для отображения AM / PM.
Хосам Али

1
Конечно, TimeSpan предназначен для представления периода времени, а не времени суток (хотя свойство DateTime.Now.TimeOfDay заставит вас поверить в обратное). Если вам нужно указать конкретное время суток, я предлагаю вам продолжить использовать класс DateTime.
JohannesH

7
Просто помните, что если TimeSpan равен или превышает 24 часа, вы получите неправильное форматирование.
JohannesH

31

Один из способов - создать DateTimeобъект и использовать его для форматирования:

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

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

Это способ, которым я знаю. Я надеюсь, что кто-то может предложить лучший способ.


14
Это действительно будет работать, только если TimeSpan меньше суток. Это не может быть таким ужасным ограничением, но оно не дает ему общего решения.
tvanfosson

Возвращает ли оно правильное значение? Dim ts As New TimeSpan (11, 22, 30, 30): Dim sss As String = Новый DateTime (ts.Ticks) .ToString ("dd.hh: mm: ss")
NeverHopeless

10

Просто. Используйте TimeSpan.ToStringс c, g или G. Дополнительная информация на MSDN


1
Спасибо за ваш ответ. Этот метод, по-видимому, является новым в .NET 4 и не существовал, когда был задан вопрос. Он также не поддерживает пользовательские форматы. Тем не менее, это ценное дополнение к ответам на эти вопросы. Еще раз спасибо.
Хосам Али



5

Лично мне нравится такой подход:

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

Вы можете сделать это так, как вам нравится, без проблем:

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

Это потрясающе:

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

1
Вам необходимо привести myTimeSpan.TotalHours к int, иначе он может быть округлен. См. Ответ Йоханнеса
codeulike

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 .

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

Все буквенные символы должны быть экранированы.


1

Я использовал код ниже. Это длинное, но все же это одно выражение, которое выдает очень дружественный вывод, поскольку не выводит дни, часы, минуты или секунды, если они имеют значение ноль.

В образце выдает результат: «4 дня 1 час 3 секунды».

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

Теперь есть намного лучший способ написать это! Попробуйте реорганизовать все обычные операции, и вы можете сделать этот код намного лучше.
Хосам Али

@Hosam Aly; Я все время учусь, вы хотите опубликовать свой улучшенный код?
panpawel

String timeComponent(int value, String name) { return value > 0 ? value + " " + name + (value > 1 ? "s" : ""); }Вызовите это для каждого компонента (например timeComponent(sp.Days, "day")), затем используйте String.joinдля вставки пробелов.
Хосам Али

1

Я использую этот метод. Я бельгиец и говорю по-голландски, поэтому множественное число часов и минут - это не просто добавление «к» в конце, а почти другое слово, чем в единственном числе.

Это может показаться длинным, но это очень читабельно, я думаю:

 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

Если вы пишете программное обеспечение, которое должно быть переведено, то это в значительной степени путь. Стандартный метод TimeSpan.ToString () слишком неуклюж, чтобы его могли понять обычные конечные пользователи, особенно если интервал превышает один день.
Нил

1

Именно такой подход я использовал для себя с условным форматированием. и я публикую это здесь, потому что я думаю, что это чистый путь.

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

пример выходов:

00:00 (Минимум)

1:43:04 (когда у нас есть часы)

15:03:01 (когда часы больше 1 цифры)

2:4:22:04 (когда у нас есть дни.)

Форматирование легко. time.Days:#0:;;\\предыдущий формат ;;предназначен для положительного значения. отрицательные значения игнорируются. и для нулевых значений мы имеем ;;\\, чтобы скрыть это в форматированной строке. обратите внимание, что экранированный обратный слеш необходим, иначе он не будет правильно отформатирован.


1

Вот мой метод расширения :

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

Пример вызова:

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

Вывод:

3 days, 14 hours, 15 minutes, 65 milliseconds

1

Это боль в VS 2010, вот мое обходное решение.

 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

SubstringМетод отлично работает , если вы хотите только часы: минуты: секунды. Это простой, чистый код и легкий для понимания.

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

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

    Console.WriteLine(formatted);

0

Вот моя версия. Он показывает только столько, сколько необходимо, обрабатывает плюрализм, негативы, и я попытался сделать его легким.

Примеры вывода

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

Код

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

Если вы хотите, чтобы формат продолжительности был похож на YouTube, учитывая количество секунд

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

Вывод:

     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

Я хотел вернуть строку типа «1 день 2 часа 3 минуты», а также принять во внимание, если, например, дни или минуты равны 0, а затем не отображать их. спасибо Джону Рашу за его ответ, который является лишь продолжением

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 ");
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.