2011-03-20 95 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