जैसा कि मैं बाद में समझा रहा हूं, मैं हमेशा TryParse
और TryParseExact
तरीकों का पक्ष लूंगा। क्योंकि वे उपयोग करने के लिए थोड़ा भारी हैं, मैंने एक विस्तार विधि लिखी है, जो पार्सिंग को बहुत आसान बनाती है:
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
इसके विपरीत Parse
, ParseExact
आदि यह एक अपवाद नहीं फेंकता है, और आपको जांचने की अनुमति देता है
if (dt.HasValue) { // continue processing } else { // do error handling }
क्या रूपांतरण सफल था (इस मामले dt
में आपके द्वारा उपयोग किया जा सकने वाला मूल्य है dt.Value
) या नहीं (इस मामले में, यह है null
)।
यहां तक कि ?.
उदाहरण के लिए "एल्विस" -प्रोसेसर जैसे सुरुचिपूर्ण शॉर्टकट का उपयोग करने की अनुमति देता है :
int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;
यहां आप यह year.HasValue
जांचने के लिए भी उपयोग कर सकते हैं कि क्या रूपांतरण सफल हुआ, और यदि यह सफल नहीं हुआ, तो year
इसमें शामिल होगा null
, अन्यथा तिथि का वर्ष भाग। यदि रूपांतरण विफल हुआ तो कोई अपवाद नहीं है।
समाधान: .ToDate () विस्तार विधि
इसे .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;
}
}
कोड के बारे में कुछ जानकारी
आप आश्चर्यचकित हो सकते हैं कि मैंने InvariantCulture
कॉलिंग का उपयोग क्यों किया है TryParseExact
: यह फ़ंक्शन को प्रारूप पैटर्न को हमेशा एक ही तरह से व्यवहार करने के लिए मजबूर करना है (अन्यथा उदाहरण के लिए "" अंग्रेजी में दशमलव विभाजक के रूप में व्याख्या की जा सकती है, जबकि यह एक समूह विभाजक या दिनांक विभाजक है। जर्मन)। याद है कि हमने पहले से ही कुछ पंक्तियों के कल्चर आधारित प्रारूप को पहले से ही उद्धृत कर दिया है ताकि यहाँ ठीक हो।
अद्यतन: .ToDate()
(मापदंडों के बिना) अब थ्रेड की वर्तमान संस्कृति के सभी सामान्य तिथि / समय पैटर्न के लिए चूक।
ध्यान दें कि हमें result
और dt
साथ की आवश्यकता है , क्योंकि TryParseExact
उपयोग करने की अनुमति नहीं है DateTime?
, जिसे हम वापस करने का इरादा रखते हैं। में सी # संस्करण 7 आप को आसान बनाने में कर सकता है 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;
या, अगर आपको यह कम पसंद है:
// 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?;
जिस स्थिति में आपको दो घोषणाओं की आवश्यकता नहीं है DateTime? result = null;
और DateTime dt;
आप इसे कोड की एक पंक्ति में कर सकते हैं। ( यदि आप चाहें तो out DateTime dt
इसके बजाय लिखने की अनुमति दी जाएगी out var dt
)।
मैंने params
कीवर्ड का उपयोग करके कोड को और सरल कर दिया है : अब आपको किसी भी तरह से 2 nd ओवरलोड विधि की आवश्यकता नहीं है ।
उपयोग का उदाहरण
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!");
}
जैसा कि आप देख सकते हैं, यह उदाहरण केवल यह देखने के लिए प्रश्न dt.HasValue
करता है कि रूपांतरण सफल हुआ था या नहीं। एक अतिरिक्त बोनस के रूप में, TryParseExact सख्त निर्दिष्ट करने की अनुमति देता है DateTimeStyles
ताकि आप ठीक से जान सकें कि एक उचित तारीख / समय स्ट्रिंग पारित हो गया है या नहीं।
उपयोग के अधिक उदाहरण
अतिभारित फ़ंक्शन आपको पार्सिंग / परिवर्तित तिथियों के लिए उपयोग किए जाने वाले मान्य स्वरूपों की एक सरणी को पास करने की अनुमति देता है जैसा कि यहां दिखाया गया है ( 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);
यदि आपके पास कुछ टेम्पलेट पैटर्न हैं, तो आप यह भी लिख सकते हैं:
var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
उन्नत उदाहरण हैं
आप ??
विफल-सुरक्षित प्रारूप में डिफ़ॉल्ट रूप से ऑपरेटर का उपयोग कर सकते हैं , जैसे
var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");
इस स्थिति में, .ToDate()
सामान्य स्थानीय संस्कृति दिनांक स्वरूपों का उपयोग करेगा, और यदि ये सभी विफल हो जाते हैं, तो यह ISO मानक प्रारूप "yyyy-MM-dd HH:mm:ss"
को कमबैक के रूप में उपयोग करने का प्रयास करेगा । इस तरह, एक्सटेंशन फ़ंक्शन आसानी से विभिन्न फ़ॉलबैक प्रारूपों को "चेन" करने की अनुमति देता है।
आप LINQ में एक्सटेंशन का उपयोग भी कर सकते हैं, इसे आज़माएं (यह .NetFiddle ऊपर है):
var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
(new[] { "15-01-2019", "15.01.2019" }).Select(s => s.ToDate(patterns)).Dump();
जो पैटर्न का उपयोग करके मक्खी पर सरणी में तिथियों को परिवर्तित करेगा और उन्हें कंसोल पर डंप करेगा।
TryParseExact के बारे में कुछ पृष्ठभूमि
अंत में, यहाँ पृष्ठभूमि के बारे में कुछ टिप्पणी दी गई है (अर्थात इस कारण मैंने इसे इस तरह लिखा है):
मैं इस विस्तार विधि में TryParseExact पसंद कर रहा हूं , क्योंकि आप अपवाद से निपटने से बचते हैं - आप अपवादों के बारे में एरिक लिपर्ट के लेख में पढ़ सकते हैं कि आपको पार्स के बजाय ट्रायपार्स का उपयोग क्यों करना चाहिए, मैं उनसे उस विषय के बारे में उद्धरण करता हूं: 2)
यह दुर्भाग्यपूर्ण डिजाइन निर्णय 1) [एनोटेशन: पार्स विधि को एक अपवाद को फेंकने के लिए] इतना घबराहट कर रहा था कि निश्चित रूप
से फ्रेमवर्क टीम ने ट्रायपर्स को शीघ्र ही लागू किया, जो कि सही काम करता है।
यह करता है, लेकिन TryParse
और TryParseExact
दोनों अभी भी एक बहुत कम से कम उपयोग करने के लिए सहज हैं: वे एक के रूप में एक गैर-आरंभिकृत चर का उपयोग करने के लिए आप के लिए मजबूर out
पैरामीटर जो व्यर्थ नहीं होना चाहिए और आप परिवर्तित कर रहे हैं आप बूलियन वापसी मान का मूल्यांकन करने की जरूरत है - या तो आपके पास if
तुरंत एक स्टेटमेंट का उपयोग करने के लिए या आपको अतिरिक्त बूलियन वैरिएबल में रिटर्न वैल्यू स्टोर करना होगा ताकि आप बाद में चेक कर सकें। और आप यह जानने के बिना लक्ष्य चर का उपयोग नहीं कर सकते कि क्या रूपांतरण सफल था या नहीं।
ज्यादातर मामलों में आप केवल यह जानना चाहते हैं कि रूपांतरण सफल था या नहीं (और निश्चित रूप से मूल्य अगर यह सफल था) , तो एक अशांत लक्ष्य चर जो सभी जानकारी को रखने के लिए वांछनीय होगा और बहुत अधिक सुरुचिपूर्ण होगा - क्योंकि पूरी जानकारी है सिर्फ एक जगह पर संग्रहीत: यह सुसंगत और प्रयोग करने में आसान है, और बहुत कम त्रुटि-प्रवण है।
मैंने जो विस्तार विधि लिखी है, वह ठीक वैसी ही है (यह आपको यह भी दिखाती है कि यदि आप उपयोग नहीं करने जा रहे हैं तो आपको हर बार कैसा कोड लिखना होगा)।
मेरा मानना .ToDate(strDateFormat)
है कि इसका लाभ यह है कि यह सरल और साफ दिखता है - मूल जितना सरल DateTime.Parse
होना चाहिए था - लेकिन यह जांचने की क्षमता के साथ कि रूपांतरण सफल था, और अपवादों को फेंक दिए बिना।
1) यहाँ क्या मतलब है कि अपवाद से निपटने (यानी एक try { ... } catch(Exception ex) { ...}
ब्लॉक) - जो जरूरी है जब आप पार्स का उपयोग कर रहे हैं क्योंकि यह एक अपवाद फेंक देगा यदि एक अमान्य स्ट्रिंग पार्स किया गया है - इस मामले में न केवल अनावश्यक है, बल्कि कष्टप्रद भी है, और अपने कोड को जटिल करना। TryParse इस सब से बचता है क्योंकि मेरे द्वारा प्रदान किया गया कोड नमूना दिखा रहा है।
2) एरिक लिपर्ट एक प्रसिद्ध स्टैकऑवरफ्लो साथी है और कुछ वर्षों से सी # कंपाइलर टीम में प्रमुख डेवलपर के रूप में माइक्रोसॉफ्ट में काम कर रहा था।