Seperti yang akan saya jelaskan nanti, saya akan selalu mendukung TryParse
dan TryParseExact
metode. Karena mereka agak besar untuk digunakan, saya telah menulis metode ekstensi yang membuat parsing lebih mudah:
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
Tidak seperti Parse
, ParseExact
dll. Itu tidak membuang pengecualian, dan memungkinkan Anda untuk memeriksa via
if (dt.HasValue) { // continue processing } else { // do error handling }
apakah konversi berhasil (dalam hal ini dt
memiliki nilai yang dapat Anda akses melalui dt.Value
) atau tidak (dalam hal ini, itu adalah null
).
Itu bahkan memungkinkan untuk menggunakan pintasan elegan seperti operator "Elvis" ?.
, misalnya:
int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;
Di sini Anda juga dapat menggunakan year.HasValue
untuk memeriksa apakah konversi berhasil, dan jika tidak berhasil maka year
akan berisi null
, jika tidak, bagian tahun tanggal. Tidak ada pengecualian yang dilemparkan jika konversi gagal.
Solusi: Metode ekstensi .ToDate ()
Cobalah di .NetFiddle
public static class Extensions
{
// Extension method parsing a date string to a DateTime?
// dateFmt is optional and allows to pass a parsing pattern array
// or one or more patterns passed as string parameters
public static DateTime? ToDate(this string dateTimeStr, params string[] dateFmt)
{
// example: var dt = "2011-03-21 13:26".ToDate(new string[]{"yyyy-MM-dd HH:mm",
// "M/d/yyyy h:mm:ss tt"});
// or simpler:
// var dt = "2011-03-21 13:26".ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
const DateTimeStyles style = DateTimeStyles.AllowWhiteSpaces;
if (dateFmt == null)
{
var dateInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
dateFmt=dateInfo.GetAllDateTimePatterns();
}
// Commented out below because it can be done shorter as shown below.
// For older C# versions (older than C#7) you need it like that:
// DateTime? result = null;
// DateTime dt;
// if (DateTime.TryParseExact(dateTimeStr, dateFmt,
// CultureInfo.InvariantCulture, style, out dt)) result = dt;
// In C#7 and above, we can simply write:
var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
style, out var dt) ? dt : null as DateTime?;
return result;
}
}
Beberapa informasi tentang kode
Anda mungkin bertanya-tanya, mengapa saya menggunakan InvariantCulture
panggilan TryParseExact
: Ini untuk memaksa fungsi untuk memperlakukan pola format selalu dengan cara yang sama (jika tidak misalnya "." Dapat diartikan sebagai pemisah desimal dalam bahasa Inggris sementara itu adalah pemisah grup atau pemisah tanggal di Jerman). Ingat kita sudah menanyakan string format berbasis budaya beberapa baris sebelumnya sehingga tidak apa-apa di sini.
Pembaruan: .ToDate()
(tanpa parameter) sekarang default untuk semua pola tanggal / waktu umum budaya saat ini utas.
Perhatikan bahwa kita perlu result
dan dt
bersama - sama, karena TryParseExact
tidak memungkinkan untuk digunakan DateTime?
, yang ingin kita kembalikan. Di C # Versi 7 Anda bisa menyederhanakan ToDate
fungsi sedikit sebagai berikut:
// in C#7 only: "DateTime dt;" - no longer required, declare implicitly
if (DateTime.TryParseExact(dateTimeStr, dateFmt,
CultureInfo.InvariantCulture, style, out var dt)) result = dt;
atau, jika Anda suka lebih pendek:
// in C#7 only: Declaration of result as a "one-liner" ;-)
var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
style, out var dt) ? dt : null as DateTime?;
dalam hal ini Anda tidak perlu dua deklarasi DateTime? result = null;
dan DateTime dt;
sama sekali - Anda dapat melakukannya dalam satu baris kode. (Ini juga akan diizinkan untuk menulis out DateTime dt
alih-alih out var dt
jika Anda lebih suka itu).
Saya telah menyederhanakan kode lebih lanjut dengan menggunakan params
kata kunci: Sekarang Anda tidak perlu 2 nd kelebihan beban metode lagi.
Contoh penggunaan
var dtStr="2011-03-21 13:26";
var dt=dtStr.ToDate("yyyy-MM-dd HH:mm");
if (dt.HasValue)
{
Console.WriteLine("Successful!");
// ... dt.Value now contains the converted DateTime ...
}
else
{
Console.WriteLine("Invalid date format!");
}
Seperti yang Anda lihat, contoh ini hanya menanyakan dt.HasValue
apakah konversi berhasil atau tidak. Sebagai bonus tambahan, TryParseExact memungkinkan untuk menentukan dengan ketat DateTimeStyles
sehingga Anda tahu persis apakah string tanggal / waktu yang tepat telah berlalu atau tidak.
Lebih Banyak Contoh penggunaan
Fungsi kelebihan beban memungkinkan Anda untuk melewatkan larik format yang valid yang digunakan untuk mem-parsing / mengubah tanggal seperti yang ditunjukkan di sini juga ( TryParseExact
secara langsung mendukung ini), misalnya
string[] dateFmt = {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
var dtStr="5/1/2009 6:32 PM";
var dt=dtStr.ToDate(dateFmt);
Jika Anda hanya memiliki beberapa pola templat, Anda juga dapat menulis:
var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
Contoh lanjutan
Anda dapat menggunakan ??
operator secara default ke format gagal-aman, mis
var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");
Dalam hal ini, .ToDate()
akan menggunakan format tanggal kultur lokal yang umum, dan jika semua ini gagal, ia akan mencoba menggunakan format standar ISO"yyyy-MM-dd HH:mm:ss"
sebagai cadangan. Dengan cara ini, fungsi ekstensi memungkinkan untuk "rantai" berbagai format fallback dengan mudah.
Anda bahkan dapat menggunakan ekstensi di LINQ, coba ini (ada di .NetFiddle di atas):
var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
(new[] { "15-01-2019", "15.01.2019" }).Select(s => s.ToDate(patterns)).Dump();
yang akan mengonversi tanggal dalam array dengan cepat menggunakan pola dan membuangnya ke konsol.
Beberapa latar belakang tentang TryParseExact
Akhirnya, Berikut adalah beberapa komentar tentang latar belakang (yaitu alasan mengapa saya menulis seperti ini):
Saya lebih suka TryParseExact dalam metode ekstensi ini, karena Anda menghindari penanganan pengecualian - Anda dapat membaca di artikel Eric Lippert tentang pengecualian mengapa Anda harus menggunakan TryParse daripada Parse, saya kutipkan kepadanya tentang topik itu: 2)
Keputusan desain yang tidak menguntungkan ini 1) [anotasi: untuk membiarkan metode Parse mengeluarkan pengecualian] begitu menjengkelkan sehingga tentu saja
tim kerangka kerja mengimplementasikan TryParse tak lama kemudian yang melakukan hal yang benar.
Ya, tetapi TryParse
dan TryParseExact
keduanya masih jauh dari nyaman untuk digunakan: Mereka memaksa Anda untuk menggunakan variabel yang tidak diinisialisasi sebagai out
parameter yang tidak boleh nullable dan saat Anda mengonversi, Anda perlu mengevaluasi nilai pengembalian boolean - baik Anda memiliki untuk menggunakan if
pernyataan segera atau Anda harus menyimpan nilai kembali dalam variabel boolean tambahan sehingga Anda dapat melakukan pemeriksaan nanti. Dan Anda tidak bisa hanya menggunakan variabel target tanpa mengetahui apakah konversi berhasil atau tidak.
Dalam kebanyakan kasus, Anda hanya ingin tahu apakah konversi berhasil atau tidak (dan tentu saja nilainya jika berhasil) , sehingga variabel target yang dapat dibatalkan yang membuat semua informasi diinginkan dan jauh lebih elegan - karena seluruh informasi hanya disimpan di satu tempat: Itu konsisten dan mudah digunakan, dan jauh lebih rentan kesalahan.
Metode ekstensi yang saya tulis tidak persis seperti itu (itu juga menunjukkan kepada Anda jenis kode apa yang harus Anda tulis setiap kali jika Anda tidak akan menggunakannya).
Saya percaya manfaatnya .ToDate(strDateFormat)
adalah tampilannya sederhana dan bersih - semudah DateTime.Parse
yang seharusnya - tetapi dengan kemampuan untuk memeriksa apakah konversi berhasil, dan tanpa membuang pengecualian.
1) Yang dimaksud di sini adalah penanganan pengecualian (yaitu try { ... } catch(Exception ex) { ...}
blok) - yang diperlukan saat Anda menggunakan Parse karena akan mengeluarkan pengecualian jika string yang tidak valid diurai - tidak hanya tidak perlu dalam kasus ini tetapi juga mengganggu, dan menyulitkan kode Anda. TryParse menghindari semua ini karena contoh kode yang saya berikan ditampilkan.
2) Eric Lippert adalah rekan StackOverflow yang terkenal dan bekerja di Microsoft sebagai pengembang utama di tim kompiler C # selama beberapa tahun.