Daha sonra açıklayacağım gibi, her zaman TryParse
ve TryParseExact
yöntemlerini tercih ederim . Kullanımı biraz hantal oldukları için, ayrıştırmayı çok daha kolay hale getiren bir uzantı yöntemi yazdım :
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
Aksine Parse
, ParseExact
bir istisna atmaz ve üzerinden kontrol etmenizi sağlar
if (dt.HasValue) { // continue processing } else { // do error handling }
dönüşümün başarılı olup olmadığı (bu durumda dt
üzerinden erişebileceğiniz bir değere sahipse dt.Value
) ya da değil (bu durumda null
).
Bu, "Elvis" -operator gibi zarif kısayolların kullanılmasına bile izin verir ?.
, örneğin:
int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;
Burada year.HasValue
, dönüşümün başarılı olup olmadığını ve başarılı year
olamadıysa null
, aksi takdirde tarihin yıl bölümünü içerecek şekilde kontrol etmek için de kullanabilirsiniz . Dönüşüm başarısız olursa herhangi bir istisna söz konusu değildir.
Çözüm: .ToDate () uzantı yöntemi
Deneyin. 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;
}
}
Kod hakkında bazı bilgiler
Ben kullandım neden, merak edebilirsiniz InvariantCulture
çağırarak TryParseExact
: Bu, örneğin (Aksi daima tedavi biçimi desenleri aynı şekilde işlev zorlamak İngilizce ondalık ayırıcı olarak yorumlanabilecek bir grup ayırıcı iken "" veya bir tarih ayırıcı içinde Almanca). Daha önce kültür bazlı format dizelerini birkaç satır önce sorguladığımızı hatırlayın, böylece burada sorun yok.
Güncelleme: .ToDate()
(parametreler olmadan) artık iş parçacığının geçerli kültürünün tüm ortak tarih / saat kalıplarını varsayılan olarak kullanıyor. Birlikte ve birlikte ihtiyacımız olduğunu
unutmayın , çünkü geri dönmek istediğimiz kullanıma izin vermez . In C # Sürüm 7 Eğer basitleştirmek olabilir aşağıdaki gibi biraz fonksiyonu:result
dt
TryParseExact
DateTime?
ToDate
// in C#7 only: "DateTime dt;" - no longer required, declare implicitly
if (DateTime.TryParseExact(dateTimeStr, dateFmt,
CultureInfo.InvariantCulture, style, out var dt)) result = dt;
veya daha da kısa isterseniz:
// 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?;
bu durumda iki bildirime ihtiyacınız yoktur DateTime? result = null;
ve DateTime dt;
hiç bir şekilde bunu tek bir kod satırında yapabilirsiniz. (Yazmak out DateTime dt
yerine yazmasına da izin verilir .out var dt
İsterseniz).
params
Anahtar kelimeyi kullanarak kodu daha da basitleştirdim : Artık 2. aşırı yüklenmiş yönteme artık ihtiyacınız yok .
Kullanım örneği
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!");
}
Gördüğünüz gibi, bu örnek dt.HasValue
dönüşümün başarılı olup olmadığını sorgular . Ekstra bir bonus olarak, TryParseExact kesin olarak belirtilmesine izin verir, DateTimeStyles
böylece uygun bir tarih / saat dizesinin geçilip geçilmediğini tam olarak bilirsiniz.
Daha fazla kullanım örneği
Aşırı yüklenmiş işlev, burada gösterildiği gibi tarihleri ayrıştırmak / dönüştürmek için kullanılan bir dizi geçerli formatı geçirmenize olanak tanır ( doğrudan bunu destekler), örn.TryParseExact
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);
Yalnızca birkaç şablon deseniniz varsa, şunları da yazabilirsiniz:
var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
Gelişmiş örnekler
Sen kullanabilirsiniz ??
fail-safe biçimi, örneğin varsayılan operatöre
var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");
Bu durumda, .ToDate()
ortak yerel kültür tarihi biçimlerini kullanır ve tüm bunlar başarısız olursa, ISO standart biçimini kullanmaya çalışır."yyyy-MM-dd HH:mm:ss"
bir yedek olarak . Bu şekilde uzatma işlevi, farklı geri dönüş biçimlerini kolayca "zincirlemenizi" sağlar.
Uzantıyı LINQ'da bile kullanabilirsiniz, bunu deneyin (yukarıdaki .NetFiddle'da bulunur):
var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
(new[] { "15-01-2019", "15.01.2019" }).Select(s => s.ToDate(patterns)).Dump();
desenleri kullanarak dizideki tarihleri anında dönüştürecek ve bunları konsola dökecektir.
TryParseExact hakkında bazı bilgiler
Son olarak, İşte arka plan hakkında bazı yorumlar (yani neden bu şekilde yazdım):
Ben tercih ediyorum TryParseExact nedeniyle, bu uzantı yönteminde durum işleme önlemek yapabilirsiniz - İstisnalar hakkında Eric Lippert en makalesinde okumak : Bunun yerine Parse daha TryParse kullanmalısınız neden, bu konu hakkında ona alıntı ) 2
Bu talihsiz tasarım kararı 1) [ek açıklama: Ayrıştırma yönteminin bir istisna atmasına izin vermek], çerçeve ekibinin kısa bir süre sonra TryParse'yi uyguladığı doğru bir şey yapıyordu
.
Kullanıyor , ancak TryParse
ve TryParseExact
her ikisi de hala kullanmaktan çok daha az: Başlatılmamış bir değişkeni out
parametre olarak kullanılmaya zorlayan bir parametre olarak kullanmaya zorlar ve dönüştürürken boolean dönüş değerini değerlendirmeniz gerekir. kullanmakif
ifadeyi hemen veya dönüş değerini ek bir boole değişkeninde saklamanız gerekir; böylece daha sonra kontrolü yapabilirsiniz. Dönüşümün başarılı olup olmadığını bilmeden hedef değişkeni kullanamazsınız.
Çoğu durumda , dönüşümün başarılı olup olmadığını (ve tabii ki başarılı olursa değeri) bilmek istersiniz , bu nedenle boş bir hedef değişken tüm bilgileri tutan arzu edilir ve çok daha zarif olur - çünkü tüm bilgiler sadece tek bir yerde saklanır: Bu tutarlı ve kullanımı kolaydır ve çok daha az hataya açıktır.
Yazdığım uzatma yöntemi tam olarak bunu yapıyor (ayrıca kullanmayacağınız her seferinde ne tür bir kod yazmanız gerektiğini gösterir).
Bunun yararı .ToDate(strDateFormat)
, orijinalin DateTime.Parse
olması gerektiği kadar basit ve temiz göründüğü , ancak dönüşümün başarılı olup olmadığını ve istisnalar atmadan kontrol edebilme yeteneği olduğuna inanıyorum .
1) Burada kastedilen, geçersiz bir dize ayrıştırılırsa bir istisna atacağı için Parse'yi kullandığınızda gerekli olan istisna işlemenin (yani bir try { ... } catch(Exception ex) { ...}
blok) sadece bu durumda değil, aynı zamanda can sıkıcı ve kodunuzu karmaşık hale getirir. Sağladığım kod örneği gösterdiği için TryParse tüm bunları önler.
2) Eric Lippert ünlü bir StackOverflow üyesidir ve Microsoft'ta C # derleyici ekibinde birkaç yıl asıl geliştirici olarak çalışıyordu.