Bagaimana saya bisa String.Format objek TimeSpan dengan format kustom di .NET?

184

Apa cara yang disarankan untuk memformat TimeSpanobjek menjadi string dengan format khusus?

Hosam Aly
sumber

Jawaban:

247

Harap perhatikan: jawaban ini untuk .Net 4.0 dan di atasnya. Jika Anda ingin memformat TimeSpan di .Net 3.5 atau di bawah, lihat jawaban JohannesH .

String format TimeSpan khusus diperkenalkan di .Net 4.0. Anda dapat menemukan referensi lengkap dari penentu format yang tersedia di halaman MSDN Custom TimeSpan Format Strings .

Berikut ini contoh string format rentang waktu:

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

( UPDATE ) dan ini adalah contoh menggunakan interpolasi string C # 6:

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

Anda harus keluar dari karakter ":" dengan tanda "\" (yang harus diloloskan kecuali jika Anda menggunakan string kata demi kata).

Kutipan dari halaman MSDN Custom TimeSpan Format Strings ini menjelaskan tentang cara keluar dari ":" dan "." karakter dalam string format:

Penentu format format TimeSpan kustom tidak menyertakan simbol pemisah placeholder, seperti simbol yang memisahkan hari dari jam, jam dari menit, atau detik dari detik pecahan. Sebaliknya, simbol-simbol ini harus dimasukkan dalam string format kustom sebagai string literal. Misalnya, "dd.hh: mm" mendefinisikan titik (.) Sebagai pemisah antara hari dan jam, dan titik dua (:) sebagai pemisah antara jam dan menit.

Dokter Jones
sumber
7
@Andrei Rinea: Benar, seperti yang dinyatakan di awal paragraf kedua saya ".Net 4 memungkinkan Anda untuk menggunakan string format khusus dengan Timespan".
Dokter Jones
1
@Edward, itu tidak benar. Dalam contoh Anda, Anda lolos dari m pertama dan pertama, jadi dengan input myTimeSpan = new TimeSpan(15, 35, 54);pernyataan myTimeSpan .ToString("hh\\mm\\ss");akan menghasilkan 15m35s54. Saya tidak berpikir itu yang Anda maksudkan karena itu akan menempatkan m setelah jam Anda dan setelah menit Anda.
Dokter Jones
1
@ Doctor Jones - Terima kasih! Maksud saya myTimeSpan.ToString ("h \\ hm \\ ms \\ s"); atau myTimeSpan.ToString (@ "h \ hm \ ms \ s"); yang memberikan 15h35m54s
Edward
2
hanya berhati-hatilah dengan solusi ini, karena itu tidak akan berfungsi dengan benar ketika bagian Jam lebih dari 24
Zoltan Tirinda
1
@ QuarK, tidak ada penentu format khusus yang melakukan itu, mereka semua memberi Anda jam yang tidak dihitung sebagai bagian dari hari. Anda bisa melakukan ini sebagai gantinya $"{myTimeSpan.TotalHours}:{myTimeSpan:mm\\:ss}". Dari sudut pandang pengguna, mungkin lebih baik untuk menampilkan hari-hari, tidak ada yang ingin secara mental mencari tahu berapa hari dalam 200+ jam.
Dokter Jones
91

Untuk .NET 3.5 dan yang lebih rendah, Anda dapat menggunakan:

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

Kode diambil dari jawaban Jon Skeet pada byte

Untuk .NET 4.0 dan di atasnya, lihat jawaban DoctaJonez .

JohannesH
sumber
Ya terima kasih. Tapi saya pikir pendekatan DateTime lebih dapat dikustomisasi, karena akan bekerja untuk format waktu yang didukung oleh DateTime. Pendekatan ini sulit digunakan untuk menunjukkan AM / PM misalnya.
Hosam Aly
1
Tentu, TimeSpan dimaksudkan untuk mewakili periode waktu, bukan waktu hari (Meskipun properti DateTime.Now.TimeOfDay akan membuat Anda percaya sebaliknya). Jika Anda perlu mewakili waktu tertentu dalam sehari, saya sarankan Anda terus menggunakan kelas DateTime.
JohannesH
7
Ingatlah bahwa jika TimeSpan sama dengan atau lebih dari 24 jam, Anda akan mendapatkan format yang salah.
JohannesH
31

Salah satu caranya adalah membuat DateTimeobjek dan menggunakannya untuk memformat:

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

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

Ini yang saya tahu. Saya harap seseorang dapat menyarankan cara yang lebih baik.

Hosam Aly
sumber
14
Ini benar-benar hanya akan berfungsi jika TimeSpan kurang dari sehari. Itu mungkin bukan pembatasan yang mengerikan, tapi itu membuatnya tidak menjadi solusi umum.
tvanfosson
Apakah ini mengembalikan nilai yang benar? Dim ts As New TimeSpan (11, 22, 30, 30): Dim sss As String = New DateTime (ts.Ticks) .ToString ("dd.hh: mm: ss")
NeverHopeless
10

Sederhana. Gunakan TimeSpan.ToStringdengan c, g atau G. Informasi lebih lanjut di MSDN

KKK
sumber
1
Terima kasih atas jawaban Anda. Metode ini tampaknya baru di .NET 4, dan tidak ada saat pertanyaan diajukan. Itu juga tidak mendukung format khusus. Namun demikian, ini merupakan tambahan yang berharga untuk jawaban atas pertanyaan ini. Terima kasih lagi.
Hosam Aly
8

Saya akan pergi dengan

myTimeSpan.ToString("hh\\:mm\\:ss");
Shehab Fawzy
sumber
Sederhana dan bersih! alternatifnya adalah @ "hh \: mm \: ss"
Xilmiki
5

Secara pribadi, saya suka pendekatan ini:

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

Anda dapat menjadikan ini sebagai kustom sesuai keinginan tanpa masalah:

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);
Tidak seorangpun
sumber
5

Ini luar biasa:

string.Format("{0:00}:{1:00}:{2:00}",
               (int)myTimeSpan.TotalHours,
               myTimeSpan.Minutes,
               myTimeSpan.Seconds);
Harpal
sumber
1
Anda perlu melemparkan myTimeSpan.TotalHours ke int - jika tidak, mungkin akan bertambah. Lihat jawaban JohannesH
kode
3

Anda juga dapat pergi dengan:

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

EDIT:

Anda juga dapat melihat Strings.Format .

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

Semua karakter literal harus diloloskan.

Ryan Williams
sumber
1

Saya menggunakan kode di bawah ini. Itu panjang, tetapi tetap merupakan satu ekspresi, dan menghasilkan output yang sangat ramah, karena tidak menghasilkan hari, jam, menit, atau detik jika mereka memiliki nilai nol.

Dalam sampel itu menghasilkan output: "4 hari 1 jam 3 detik".

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
sumber
Sekarang ada cara yang lebih baik untuk menulis ini! Cobalah untuk memperbaiki semua operasi umum, dan Anda dapat membuat kode ini terlihat jauh lebih baik.
Hosam Aly
@ Husam Aly; Saya belajar sepanjang waktu, apakah Anda ingin memposting kode yang ditingkatkan?
panpawel
String timeComponent(int value, String name) { return value > 0 ? value + " " + name + (value > 1 ? "s" : ""); }Sebut itu untuk setiap komponen (misalnya timeComponent(sp.Days, "day")), lalu gunakan String.joinuntuk memasukkan spasi.
Hosam Aly
1

Saya menggunakan metode ini. Saya orang Belgia dan berbicara bahasa Belanda sehingga jam dan menit tidak hanya menambahkan 's' sampai akhir tetapi hampir kata yang berbeda dari tunggal.

Mungkin kelihatannya lama tapi sangat mudah dibaca menurut saya:

 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
sumber
Jika Anda menulis perangkat lunak yang perlu diterjemahkan, maka ini cara yang bagus. TimeSpan.ToString () standar terlalu kikuk untuk dipahami oleh pengguna akhir biasa, terutama ketika rentangnya jika lebih dari sehari.
Neil
1

Ini adalah pendekatan yang saya gunakan diri saya dengan pemformatan bersyarat. dan saya mempostingnya di sini karena saya pikir ini cara yang bersih.

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

contoh output:

00:00 (minimum)

1:43:04 (ketika kita punya jam)

15:03:01 (ketika jam lebih dari 1 digit)

2:4:22:04 (ketika kita punya hari.)

Pemformatannya mudah. time.Days:#0:;;\\format sebelumnya ;;adalah ketika nilai positif. nilai-nilai negatif diabaikan. dan untuk nilai nol yang kita miliki ;;\\untuk menyembunyikannya dalam string yang diformat. perhatikan bahwa backslash yang lolos diperlukan jika tidak akan memformat dengan benar.

M.kazem Akhgary
sumber
1

Inilah metode ekstensi saya :

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

Contoh panggilan:

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

Keluaran:

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

Ini adalah rasa sakit di VS 2010, inilah solusi saya.

 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
sumber
1

The SubstringMetode bekerja sempurna bila Anda hanya ingin Jam: Menit: Detik. Sederhana, kode bersih dan mudah dimengerti.

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

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

    Console.WriteLine(formatted);
APK
sumber
0

Ini versi saya. Ini hanya menunjukkan sebanyak yang diperlukan, menangani pluralisasi, negatif, dan saya mencoba membuatnya ringan.

Contoh Keluaran

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

Kode

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
sumber
0

Jika Anda menginginkan format durasi yang mirip dengan youtube, berikan jumlah detik

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

Keluaran:

     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
sumber
0

Saya ingin mengembalikan string seperti "1 hari 2 jam 3 menit" dan juga memperhitungkan jika misalnya hari atau minut adalah 0 dan kemudian tidak menunjukkannya. terima kasih kepada John Rasch untuk jawaban yang milikku hampir tidak ada dari

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