2011-03-20 93 views
109

我已經日期和時間在一個字符串格式化像一個:解析字符串的DateTime在C#

"2011-03-21 13:26" //year-month-day hour:minute 

如何可以解析它System.DateTime

如果可能,我想使用DateTime.Parse()DateTime.ParseExact()等功能,以便能夠手動指定日期格式。

+17

那麼,爲什麼你不使用DateTime.Parse? – 2011-03-20 02:06:22

+7

我是downvoters之一。這是因爲你原來的問題(http://stackoverflow.com/revisions/3c6789f2-8a6b-4557-bafc-1b8eb4d5f8c4/view-source)表示你想使用DateTime.Parse(),但你沒有說明爲什麼你無法使用它。這使得它看起來像是一個無稽之談,特別是因爲一個簡單的檢查會清楚地表明cacois是正確的:你的字符串「2011-03-21 13:26」對於DateTime.Parse()不是問題。最後,您在原始問題中沒有提及ParseExact()。你一直等到* Mitch的回答之後,在編輯中添加這個。 – anon 2011-03-20 04:31:41

+1

我只是喜歡那些沒有給出任何理由的評論性問題。 – Hooch 2015-04-21 11:46:41

回答

183

DateTime.Parse()將嘗試找出給定日期的格式,它通常會做得很好。如果你能保證日期總是會在一個給定的格式,那麼你可以使用ParseExact()

string s = "2011-03-21 13:26"; 

DateTime dt = 
    DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture); 

(但是請注意,它通常是使用更安全的的TryParse方法之一,以防日期不是預期的格式)

構建格式化字符串時一定要檢查Custom Date and Time Format Strings,尤其要注意字母和大小寫(即「MM」和「mm」意思是非常不同的東西)。

對於C#格式化字符串另一個有用的資源是String Formatting in C#

+3

更正 - 它總是更安全;)如果您正在調用帶有例外的方法,請在可能的情況下首先檢查例外情況。 – Gusdor 2013-08-27 12:36:14

+2

我會說永遠傳遞你的文化更安全。我寧願有一個例外,而不是將「01-02-2013」​​誤解爲一月二號或二月一號。 – Carra 2013-10-14 08:38:29

+1

@Carra:ISO8601格式的日期(即yyyy-mm-dd)總是以正確的方式解釋,這就是爲什麼我們使用ISO8601格式的日期... – 2014-07-16 02:41:48

9
var dateStr = @"2011-03-21 13:26"; 
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture); 

看看這個link其他格式字符串!

+1

HH =小時,ss =秒...... – 2011-03-20 02:10:18

3

把一個人類可讀的字符串的值到.NET的DateTime有這樣的代碼:

DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null); 
32

由於我後來解釋,我總是會青睞TryParseTryParseExact方法。因爲他們是有點笨重的使用,我寫了擴展方法這使得解析容易得多:

var dtStr = "2011-03-21 13:26"; 
DateTime? dt = dtStr.toDate("yyyy-MM-dd HH:mm"); 

不像ParseParseExact等它不會拋出異常,並允許您通過

檢查

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,否則爲該日期的年份部分。如果轉換失敗,則不會拋出異常。

Try it in .NetFiddle

public static class Extensions 
{ 
    public static DateTime? toDate(this string dateTimeStr, 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"}); 
     const DateTimeStyles style = DateTimeStyles.AllowWhiteSpaces; 
     if (dateFmt == null) 
     { 
     var dateInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat; 
     dateFmt=dateInfo.GetAllDateTimePatterns(); 
     } 
     DateTime? result = null; 
     DateTime dt; 
     if (DateTime.TryParseExact(dateTimeStr, dateFmt, 
     CultureInfo.InvariantCulture, style, out dt)) result = dt; 
     return result; 
    } 

    public static DateTime? toDate(this string dateTimeStr, string dateFmt=null) 
    { 
     // example: var dt="2011-03-21 13:26".toDate("yyyy-MM-dd HH:mm"); 
     // or simply var dt="2011-03-21 13:26".toDate();   
     // call overloaded function with string array param 
     string[] dateFmtArr = dateFmt == null ? null : new string[] { dateFmt }; 
     return toDate(dateTimeStr, dateFmtArr); 
    } 
} 

更新:.toDate()(不帶參數)現在默認線程的當前文化的所有常見的日期/時間模式。
注意我們需要resultdt在一起,因爲TryParseExact不允許使用我們打算返回的DateTime?。 在C#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; 

(這也將被允許寫out DateTime dt代替out var dt。)

實施例:

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,以便您確切知道是否已傳遞適當的日期/時間字符串。


N.B.重載函數允許您傳遞有效格式數組,用於解析/轉換日期,如hereTryParseExact直接支持這個)。

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

然而,爲了保持代碼的短,我只用TryParseExact的字符串數組超載,因爲它沒有一個通用的參數工作。

高級例如:
可以使用??運營商默認爲自動防故障的格式,例如

var dtStr = "2017-12-30 11:37:00"; 
var dt = (dtStr.toDate()) ?? dtStr.toDate("yyyy-MM-dd HH:mm:ss"); 

在這種情況下,.toDate()將使用共同的地方文化的日期格式,如果所有這些失敗,它會嘗試使用ISO standard格式"yyyy-MM-dd HH:mm:ss"作爲後備。這樣,擴展功能可以輕鬆「鏈接」不同的後備格式。


最後,下面是關於背景的一些評論。爲什麼我這樣寫它的原因):我在此擴展方法寧願TryParseExact

,因爲你避免異常處理 - 你可以read in Eric Lippert's article about exceptions爲什麼你應該使用的TryParse而不是解析,我引用了他有關該主題:2)

不幸設計決策1) [註釋:到 讓Parse方法拋出異常]是如此令人煩惱的是當然 框架團隊不久之後實施了TryParse這是正確的事情。

確實如此,但TryParseTryParseExact都還比舒適的少了很多使用方法:他們強迫你使用一個未初始化的變量作爲out參數,不能可爲空並且當你轉換你需要評估布爾返回值 - 要麼立即使用if語句,要麼必須將返回值存儲在其他布爾變量中,以便稍後執行檢查。如果不知道轉換是否成功,您不能只使用目標變量。

你只是想知道轉換是否成功與否(當然如果值是成功的)大多數情況下,這樣一個爲空的目標變量這使所有的信息將是可取的,多更優雅 - 因爲整個信息只是存儲在一個地方:這是一致的,易於使用,而且更不容易出錯。

我寫的擴展方法確實如此(它也顯示瞭如果你不打算使用它,你每次都要寫什麼樣的代碼)。

我認爲.toDate(strDateFormat)的好處是它看起來簡單而乾淨 - 像原來的DateTime.Parse一樣簡單 - 但能夠檢查轉換是否成功,並且不會拋出異常。


1)這是怎麼意思是異常處理(即try { ... } catch(Exception ex) { ...}塊) - 當你使用解析,因爲如果無效的字符串被解析它會拋出一個異常,是必要的 - 在這種情況下不僅是不必要的,而且令人討厭,並且使代碼複雜化。 TryParse避免了所有這些,因爲我提供的代碼示例正在顯示。


2)埃裏克利珀是著名StackOverflow fellow,在微軟工作作爲對C#編譯器團隊主要開發了幾年。

1

您還可以使用XmlConvert.ToDateString

VAR dateStr = 「2011-03-21 13:26」; var parsedDate = XmlConvert。ToDateTime(dateStr,「yyyy-MM-dd hh:mm」);

這是好事,指定的日期種類,像

變種anotherParsedDate = DateTime.ParseExact(dateStr, 「YYYY-MM-DD HH:MM」,CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal);

關於不同解析選項的更多細節http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html