Mengapa string format TimeSpan khusus ini berhenti berfungsi di .NET 4?

Pertimbangkan kode ini (diisi dengan contoh):

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM");
DateTime dt2 = DateTime.Parse("6/30/2010 9:33:00.7654321 AM");

TimeSpan ts = dt1 - dt2;

Console.WriteLine(string.Format( "{0:d.hh:mm:ss.ff}", ts ));

Ini mewakili sepotong kode yang telah saya kerjakan setidaknya sejak .NET 1.1.

Ini berfungsi dengan baik di 1.1 hingga 3.5 dengan output berikut (untuk input tiruan ini):

30.00:00:28.3580246

Tapi sekarang saya melihatnya mati di .NET 4 dengan pesan kesalahan:

Input string was not in a correct format.

Jadi seolah-olah .NET 4 tiba-tiba memutuskan tidak menyukai format ini karena perbedaan waktu. Mengubah jalur menjadi, katakanlah

Console.WriteLine(string.Format( "{0}", ts.ToString("d.hh:mm:ss.ff") ));

memiliki efek yang sama.

Sekarang hal yang saya perhatikan adalah jika saya melakukan .ToString() default saya mendapatkan hasil yang sama. Saya yakin proses pemikirannya adalah bahwa ini adalah polis asuransi terhadap perubahan format default di versi mendatang. Tapi sekarang sepertinya itu bukan pilihan.

Adakah yang tahu mengapa hal ini berubah dan apakah saya melakukan kesalahan atau apakah ada cara praktik terbaik untuk melakukan apa yang ingin saya capai?


person Tom Kidd    schedule 30.07.2010    source sumber


Jawaban (5)


Terdapat saklar konfigurasi untuk memulihkan perilaku lama Rentang Waktu.

person Mitch Wheat    schedule 30.07.2010
comment
Jadi pada dasarnya string format itu tidak melakukan apa pun selama ini. Luar biasa. Terima kasih. - person Tom Kidd; 30.07.2010
comment
@Schnapple Tepatnya. Di .NET 3.5 dan sebelumnya, struct TimeSpan bukan IFormattable. Ketika string.Format dan metode terkait melihat sesuatu seperti {0:something} dan argumen yang diberikan bukan IFormattable, mereka tidak punya tempat untuk meletakkan string format tersebut, dan mereka membuangnya begitu saja. Itulah yang terjadi pada kode Anda hingga .NET 4.0 tiba. - person Jeppe Stig Nielsen; 07.07.2013

Alternatif untuk peralihan konfigurasi adalah perubahan format yang kompatibel dengan versi sebelumnya.

Console.WriteLine(string.Format( "{0:hh\\:mm\\:ss.ff}", ts )); 

Solusi ini detailnya di sini.

person wilk    schedule 30.08.2010
comment
Ini memperbaikinya untuk saya :) - person Fiona - myaccessible.website; 10.09.2013

Faktanya, string format gabungan yang Anda gunakan dalam kode Anda tidak berpengaruh sama sekali, karena TimeSpan tidak mendukung string format khusus (.NET ‹ 4.0 ).

yaitu TimeSpan Anda akan selalu diformat seperti 30.00:00:28.3580246 apa pun format stringnya.

Dari MSDN:

Di versi .NET Framework sebelumnya, struktur TimeSpan tidak mengimplementasikan IFormattable dan tidak mendukung format string.

Namun, banyak pengembang yang salah berasumsi bahwa TimeSpan mendukung sekumpulan string format dan menggunakannya dalam operasi pemformatan gabungan dengan metode seperti String.Format. Biasanya, jika suatu tipe mengimplementasikan IFormattable dan mendukung format string, panggilan ke metode pemformatan dengan format string yang tidak didukung biasanya memunculkan FormatException. Namun, karena TimeSpan tidak mengimplementasikan IFormattable, runtime mengabaikan string format dan malah memanggil metode TimeSpan.ToString(). Artinya, meskipun string format tidak berpengaruh pada operasi pemformatan, kehadirannya tidak menghasilkan FormatException.

person Saeb Amini    schedule 25.08.2014

Seperti yang ditunjukkan oleh Mitch Wheat dan Saeb Amini di mereka jawaban, TimeSpan tidak mengimplementasikan IFormattable sebelum .NET 4.0. Akibatnya, string format tidak berpengaruh pada keluaran TimeSpan.ToString() karena diabaikan.

Namun, karena TimeSpan tidak mengimplementasikan IFormattable, runtime mengabaikan string format dan malah memanggil metode TimeSpan.ToString. Artinya, meskipun string format tidak berpengaruh pada operasi pemformatan, kehadirannya tidak menghasilkan FormatException.

Sumber

Oleh karena itu, jika Anda ingin memformat nilai TimeSpan di semua versi kerangka .NET, lebih baik mengonversi nilai TimeSpan menjadi DateTime lalu memformat hasilnya seperti yang ditunjukkan di bawah ini:

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM");
DateTime dt2 = DateTime.Parse("6/30/2010 9:33:00.7654321 AM");

TimeSpan ts = dt1 - dt2;

Console.WriteLine(String.Format("{0:d.hh:mm:ss.ff}", new DateTime(ts.Ticks))) 
// prints 30.00:00:28.36
person Alex Essilfie    schedule 02.01.2015

Saya telah menempelkan kode Anda dan sepertinya ada masalah budaya:

dengan .NET 2, FormatException juga ditampilkan

Jika saya menentukan budaya AS (budaya adalah fr-FR secara default), kodenya berfungsi:

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM", CultureInfo.GetCultureInfo("en-US"));

Anda juga dapat menentukan budaya Invarian untuk mengabaikan budaya tersebut

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM", CultureInfo.InvariantCulture);
person Florian    schedule 30.07.2010
comment
Saya pikir Anda menyukai sesuatu dengan budayanya, tetapi bukan baris DateTime yang membuat saya cocok, melainkan string format TimeSpan. Bahkan jika saya menentukan budaya dalam TimeSpan ToString dan kedua metode DateTime.Parse, saya masih mendapatkan hasil yang sama. - person Tom Kidd; 30.07.2010