เหตุใดสตริงรูปแบบ TimeSpan นี้จึงหยุดทำงานใน .NET 4

พิจารณารหัสนี้ (มีตัวอย่าง):

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

นี่เป็นตัวแทนของโค้ดบางส่วนที่ฉันใช้งานตั้งแต่ .NET 1.1 เป็นอย่างน้อย

มันทำงานได้ดีใน 1.1 ถึง 3.5 โดยมีเอาต์พุตต่อไปนี้ (สำหรับอินพุตจำลองเหล่านี้):

30.00:00:28.3580246

แต่ตอนนี้ฉันเห็นว่ามันตายใน .NET 4 พร้อมข้อความแสดงข้อผิดพลาด:

Input string was not in a correct format.

เหมือนกับว่า .NET 4 ตัดสินใจทันทีว่าไม่ชอบรูปแบบนี้เนื่องจากความแตกต่างของเวลา เปลี่ยนแนวเป็นว่า.

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

มีผลเช่นเดียวกัน

ตอนนี้สิ่งที่ฉันสังเกตเห็นก็คือถ้าฉันใช้ค่าเริ่มต้น .ToString() ฉันจะได้ผลลัพธ์เดียวกัน ฉันเชื่อว่ากระบวนการคิดคือนี่เป็นกรมธรรม์ประกันภัยสำหรับรูปแบบเริ่มต้นที่เปลี่ยนแปลงในเวอร์ชันอนาคต แต่ตอนนี้ดูเหมือนว่านั่นจะไม่ใช่ตัวเลือกด้วยซ้ำ

ไม่มีใครรู้ว่าเหตุใดสิ่งนี้จึงเปลี่ยนแปลง และถ้าฉันทำอะไรผิดหรือมีแนวทางปฏิบัติที่ดีที่สุดในสิ่งที่ฉันพยายามทำให้สำเร็จหรือไม่


person Tom Kidd    schedule 30.07.2010    source แหล่งที่มา


คำตอบ (5)


มีสวิตช์การกำหนดค่าเพื่อคืนค่าลักษณะการทำงานเก่าของ ช่วงเวลา

person Mitch Wheat    schedule 30.07.2010
comment
โดยพื้นฐานแล้วสตริงรูปแบบนั้นไม่ได้ทำอะไรเลยตลอดเวลานี้ โดดเด่น. ขอบคุณ. - person Tom Kidd; 30.07.2010
comment
@Schnapple เป๊ะเลย ใน .NET 3.5 และรุ่นก่อนหน้า โครงสร้าง TimeSpan ไม่ใช่ IFormattable เมื่อ string.Format และวิธีการที่เกี่ยวข้องเห็นบางอย่างเช่น {0:something} และอาร์กิวเมนต์ที่ให้มาไม่ใช่ IFormattable พวกเขาไม่มีที่ที่จะใส่สตริงรูปแบบนั้น และพวกเขาก็ทิ้งมันไป นั่นคือสิ่งที่เกิดขึ้นในโค้ดของคุณจนกระทั่ง .NET 4.0 มาถึง - person Jeppe Stig Nielsen; 07.07.2013

ทางเลือกอื่นนอกเหนือจากสวิตช์การกำหนดค่าคือการเปลี่ยนแปลงรูปแบบที่เข้ากันได้กับเวอร์ชันก่อนหน้า

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

วิธีแก้ไขนี้มีรายละเอียด ที่นี่< /ก>.

person wilk    schedule 30.08.2010
comment
สิ่งนี้แก้ไขได้สำหรับฉัน :) - person Fiona - myaccessible.website; 10.09.2013

อันที่จริง สตริงรูปแบบผสมที่คุณใช้ในโค้ดของคุณ ไม่มีผลกระทบใดๆ เลย เนื่องจาก TimeSpan ไม่ สนับสนุนสตริงรูปแบบที่กำหนดเอง (.NET ‹ 4.0 ).

นั่นคือ TimeSpan ของคุณจะถูกจัดรูปแบบเป็น 30.00:00:28.3580246 เสมอ ไม่ว่าสตริงรูปแบบจะเป็นอย่างไรก็ตาม

จาก MSDN:

ใน .NET Framework รุ่นก่อนหน้านี้ โครงสร้าง TimeSpan ไม่ได้ใช้ IFormattable และไม่สนับสนุนสตริงรูปแบบ

อย่างไรก็ตาม นักพัฒนาจำนวนมากเข้าใจผิดคิดว่า TimeSpan รองรับชุดสตริงรูปแบบ และใช้ในการจัดรูปแบบแบบผสมด้วยวิธีการต่างๆ เช่น String.Format โดยปกติแล้ว หากประเภทใช้ IFormattable และรองรับสตริงรูปแบบ การเรียกไปยังวิธีการจัดรูปแบบด้วยสตริงรูปแบบที่ไม่รองรับมักจะส่งไฟล์ FormatException อย่างไรก็ตาม เนื่องจาก TimeSpan ไม่ได้ใช้ IFormattable รันไทม์จึงละเว้นสตริงรูปแบบและเรียกเมธอด TimeSpan.ToString() แทน ซึ่งหมายความว่า แม้ว่าสตริงรูปแบบจะไม่ส่งผลต่อการดำเนินการจัดรูปแบบ แต่การมีอยู่ของสตริงเหล่านี้ไม่ได้ส่งผลให้เกิด FormatException

person Saeb Amini    schedule 25.08.2014

ตามที่ระบุโดย Mitch Wheat และ Saeb Amini ในของพวกเขา คำตอบ, TimeSpan ไม่ได้ใช้ IFormattable ก่อน .NET 4.0 ดังนั้น สตริงรูปแบบ ไม่มีผลกระทบ กับเอาต์พุต TimeSpan.ToString() เนื่องจากถูกละเว้น

อย่างไรก็ตาม เนื่องจาก TimeSpan ไม่ได้ใช้ IFormattable รันไทม์ ละเว้นสตริงรูปแบบ และเรียกเมธอด TimeSpan.ToString แทน ซึ่งหมายความว่า แม้ว่าสตริงรูปแบบจะไม่ส่งผลต่อการดำเนินการจัดรูปแบบ แต่การมีอยู่ของสตริงเหล่านี้ไม่ได้ส่งผลให้เกิด FormatException

แหล่งที่มา

กล่าวคือ หากคุณต้องการจัดรูปแบบค่า TimeSpan ในทุกเวอร์ชันของเฟรมเวิร์ก .NET จะเป็นการดีกว่ามากหากแปลงค่า TimeSpan เป็น DateTime แล้วจึงจัดรูปแบบผลลัพธ์ดังที่แสดงด้านล่าง:

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

ฉันได้วางโค้ดของคุณแล้วและดูเหมือนว่าจะเป็นปัญหาวัฒนธรรม:

ด้วย. NET 2 FormatException ก็ถูกส่งออกไปเช่นกัน

ถ้าฉันระบุวัฒนธรรม us (วัฒนธรรมคือ fr-FR โดยค่าเริ่มต้น) รหัสใช้งานได้:

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

คุณยังสามารถระบุวัฒนธรรมที่ไม่แปรเปลี่ยนเพื่อละเว้นวัฒนธรรมนั้นได้

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM", CultureInfo.InvariantCulture);
person Florian    schedule 30.07.2010
comment
ฉันคิดว่าคุณกำลังทำอะไรบางอย่างเกี่ยวกับวัฒนธรรม แต่ไม่ใช่บรรทัด DateTime ที่ทำให้ฉันพอดี แต่เป็นสตริงรูปแบบ TimeSpan แม้ว่าฉันจะระบุวัฒนธรรมใน TimeSpan ToString และทั้งสองวิธี DateTime.Parse ฉันก็ยังคงได้รับเหมือนเดิม - person Tom Kidd; 30.07.2010