Як я можу String.Format об'єкт TimeSpan з користувацьким форматом у .NET?


Відповіді:


247

Зверніть увагу: ця відповідь призначена для .Net 4.0 і вище. Якщо ви хочете відформатувати TimeSpan у .Net 3.5 або нижче, дивіться відповідь Йоханнеса .

Спеціальні рядки формату TimeSpan були введені в .Net 4.0. Ви можете знайти повну посилання на наявні специфікатори формату на сторінці MSDN Custom String Format Strings .

Ось приклад рядка формату часового простору:

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

( ОНОВЛЕННЯ ), і ось приклад з використанням інтерполяції рядків C # 6:

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

Вам потрібно уникнути символу ":" із символом "\" (який сам слід уникнути, якщо ви не використовуєте дослівний рядок).

Цей уривок зі сторінки користувальницьких рядків формату MSDN пояснює можливість виходу зі строків ":" та "." символів у рядку формату:

Спеціальні специфікатори формату TimeSpan не включають символи роздільника заповнювачів, наприклад символи, які розділяють дні від годин, годин від хвилин або секунд від дробових секунд. Натомість ці символи повинні бути включені у рядок спеціального формату як літеральні рядки. Наприклад, "dd.hh: mm" визначає період (.) Як роздільник між днями та годинами, а двокрапка (:) як роздільник між годинами та хвилинами.


7
@Andrei Rinea: Правильно, як зазначено на початку мого другого абзацу, ".Net 4 дозволяє використовувати рядки власного формату з Timespan".
Лікар Джонс

1
@Edward, це не зовсім правильно. У вашому прикладі ви уникаєте першого m та першого s, тож із введенням myTimeSpan = new TimeSpan(15, 35, 54);оператора ви myTimeSpan .ToString("hh\\mm\\ss");отримаєте результат 15m35s54. Я не думаю, що це те, що ти задумав, оскільки воно буде розміщувати м через години та пізніше.
Лікар Джонс

1
@Doctor Jones - Дякую! Я мав на увазі 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);

Код узятий з Jon тарілочках відповідь на байтах

Для .NET 4.0 і вище див. Відповідь DoctaJonez .


Так дякую. Але я думаю, що підхід DateTime є більш налаштованим, оскільки він буде працювати в будь-якому форматі часу, підтримуваному DateTime. Цей підхід важко використовувати, наприклад, для показу AM / PM.
Хосам Алі

1
Звичайно, TimeSpan призначений для відображення періоду часу, а не часу доби (Навіть незважаючи на те, що властивість DateTime.Now.TimeOfDay вважає вас протилежним). Якщо вам потрібно представити конкретний час доби, я пропоную вам продовжити використання класу DateTime.
ЙоханнесH

7
Пам'ятайте лише, що якщо TimeSpan дорівнює або більше 24 годин, ви отримаєте неправильне форматування.
ЙоханнесH

31

Один із способів - створити DateTimeоб'єкт і використовувати його для форматування:

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

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

Це я знаю. Сподіваюся, хтось може запропонувати кращий шлях.


14
Це дійсно буде працювати лише в тому випадку, якщо Час роботи складає менше ніж день. Це може бути не таким страшним обмеженням, але воно не дає загального рішення.
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 - інакше він може отримати округлення. Дивіться відповідь Йоханнеса
подібний до кодексу

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.