public static class Extensions
{
/// Extension method parsing a date string to a DateTime? <para/>
/// <summary>
/// </summary>
/// <param name="dateTimeStr">The date string to parse</param>
/// <param name="dateFmt">dateFmt is optional and allows to pass
/// a parsing pattern array or one or more patterns passed
/// as string parameters</param>
/// <returns>Parsed DateTime or null</returns>
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();
}
var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
style, out var dt) ? dt : null as DateTime?;
return result;
}
}
更新:.ToDate()(无参数)现在默认为线程当前区域性的所有常用日期/时间模式。 注意我们需要result和dt一起使用,因为TryParseExact不允许使用DateTime?,我们打算返回DateTime?。在C# Version 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)。 旧的C#风格会以下面的方式要求它(我从上面的代码中删除了它):
// DateTime? result = null;
// DateTime dt;
// if (DateTime.TryParseExact(dateTimeStr, dateFmt,
// CultureInfo.InvariantCulture, style, out dt)) result = dt;
我使用params关键字进一步简化了代码:现在你不再需要第二个重载方法了。
用法示例
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!");
}
var strDateArray = new[] { "15-01-2019", "15.01.2021" };
var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
var dtRange = strDateArray.Select(s => s.ToDate(patterns));
dtRange.Dump();
它将使用模式动态转换数组中的日期,并将其转储到控制台。
TryParseExact的一些背景知识
最后,这里有一些关于背景的评论(即我这样写的原因): 在这个扩展方法中,我更喜欢TryParseExact,因为你避免了异常处理-你可以read in Eric Lippert's article about exceptions 3)为什么你应该使用TryParse而不是Parse,我引用他关于这个主题的话:2) 这个不幸的设计决定1)[注解:让Parse方法抛出异常]是如此令人烦恼,当然框架团队随后不久就实现了TryParse,它做了正确的事情。 确实如此,但是TryParse和TryParseExact使用起来还是不太舒服:它们强迫你使用一个未初始化的变量作为out参数,这个参数不能为空,并且在转换时你需要计算布尔返回值--要么你必须立即使用一个if语句,要么你必须将返回值存储在一个额外的布尔变量中,这样你就可以在以后进行检查。在不知道转换是否成功的情况下,不要只使用目标变量。 在大多数情况下,你只想知道 * 转换是否成功(当然,如果成功了,还需要知道值)*,所以一个可空的目标变量将保留所有信息,这将是可取的,而且更优雅-因为整个信息只是存储在一个地方:这是一致的,易于使用,而且更不容易出错。
9条答案
按热度按时间7rfyedvj1#
DateTime.Parse()
将尝试找出给定日期的格式,它通常做得很好。如果你可以保证日期总是给定的格式,那么你可以使用ParseExact()
:(But注意,如果日期不是预期的格式,通常使用TryParse方法之一更安全)
在构造格式字符串时,一定要检查Custom Date and Time Format Strings,特别要注意字母的数量和大小写(即“MM”和“mm”的含义非常不同)。
另一个有用的C#格式字符串资源是String Formatting in C#
2wnc66cl2#
正如我后面解释的,我总是喜欢
TryParse
和TryParseExact
方法。因为它们使用起来有点笨重,我写了一个扩展方法,它使解析更容易:或者更简单地说,如果你想隐式地使用当前区域性的日期模式,你可以像这样使用它:
在这种情况下,不需要指定特定的模式。如果未指定,则使用当前区域性(在当前线程中)的默认DateTime模式。
与
Parse
、ParseExact
等不同,它不会抛出异常,并允许您通过if (dt.HasValue) { // continue processing } else { // do error handling }
转换是否成功(在本例中,
dt
的值可以通过dt.Value
访问)(在本例中,它是null
)。这甚至允许使用优雅的快捷方式,如“Elvis”操作符
?.
,例如:这里你也可以使用
year.HasValue
来检查转换是否成功,如果没有成功,那么year
将包含null
,否则是日期的年份部分。如果转换失败,不会抛出异常。解决方案:** .ToDate() 扩展方法**
Try it in .NetFiddle
代码的一些信息
您可能会想,为什么我使用
InvariantCulture
调用TryParseExact
:这是为了强制函数始终以相同的方式处理格式模式(否则,例如“.”在英语中可能被解释为小数点分隔符,而在德语中它是组分隔符 * 或 * 日期分隔符)。回想一下,我们已经在几行之前查询了基于区域性的格式字符串,所以这里没有问题。更新:
.ToDate()
(无参数)现在默认为线程当前区域性的所有常用日期/时间模式。注意我们需要
result
和dt
一起使用,因为TryParseExact
不允许使用DateTime?
,我们打算返回DateTime?
。在C# Version 7中,可以将ToDate
函数简化如下:或者,如果你喜欢它更短:
在这种情况下,您根本不需要两个声明
DateTime? result = null;
和DateTime dt;
-您可以在一行代码中完成它。(如果您愿意,也可以编写out DateTime dt
而不是out var dt
)。旧的C#风格会以下面的方式要求它(我从上面的代码中删除了它):
我使用
params
关键字进一步简化了代码:现在你不再需要第二个重载方法了。用法示例
正如你所看到的,这个例子只是查询
dt.HasValue
来查看转换是否成功。作为一个额外的好处,TryParseExact允许指定严格的DateTimeStyles
,这样你就可以确切地知道是否传递了正确的日期/时间字符串。更多用法示例
重载函数允许你传递一个有效格式数组,用于解析/转换日期,如here所示(
TryParseExact
直接支持),例如。如果你只有几个模板模式,你也可以这样写:
高级示例
您可以使用
??
操作符来默认为故障安全格式,例如:在这种情况下,
.ToDate()
将使用常见的本地区域性日期格式,如果所有这些都失败,它将尝试使用ISO standard"yyyy-MM-dd HH:mm:ss"
作为后备。这样,扩展函数可以轻松地“链接”不同的后备格式。你甚至可以在LINQ中使用扩展,试试这个(它在上面的.NetFiddle中):
它将使用模式动态转换数组中的日期,并将其转储到控制台。
TryParseExact的一些背景知识
最后,这里有一些关于背景的评论(即我这样写的原因):
在这个扩展方法中,我更喜欢TryParseExact,因为你避免了异常处理-你可以read in Eric Lippert's article about exceptions 3)为什么你应该使用TryParse而不是Parse,我引用他关于这个主题的话:2)
这个不幸的设计决定1)[注解:让Parse方法抛出异常]是如此令人烦恼,当然框架团队随后不久就实现了TryParse,它做了正确的事情。
确实如此,但是
TryParse
和TryParseExact
使用起来还是不太舒服:它们强迫你使用一个未初始化的变量作为out
参数,这个参数不能为空,并且在转换时你需要计算布尔返回值--要么你必须立即使用一个if
语句,要么你必须将返回值存储在一个额外的布尔变量中,这样你就可以在以后进行检查。在不知道转换是否成功的情况下,不要只使用目标变量。在大多数情况下,你只想知道 * 转换是否成功(当然,如果成功了,还需要知道值)*,所以一个可空的目标变量将保留所有信息,这将是可取的,而且更优雅-因为整个信息只是存储在一个地方:这是一致的,易于使用,而且更不容易出错。
我所编写的扩展方法正是这样做的(它还向您展示了如果您不打算使用它,每次都必须编写什么样的代码)。
我相信
.ToDate(strDateFormat)
的好处是它看起来简单而干净--就像最初的DateTime.Parse
一样简单--但是能够检查转换是否成功,并且不会抛出异常。try { ... } catch(Exception ex) { ...}
块)-这在使用Parse时是必要的,因为如果解析出无效字符串,它会抛出异常-在这种情况下不仅不必要,而且令人讨厌,并使代码复杂化。TryParse避免了这一切,正如我提供的代码示例所示。*2)Eric Lippert是著名的StackOverflow fellow,曾在微软C#编译器团队担任首席开发人员几年。
3)不幸的是,微软已经从他们的MSDN站点上删除了这篇文章。如果有人在其他URL上找到它,请让我知道,我会更新它。
yhuiod9q3#
查看link以获取其他格式字符串!
ddarikpa4#
DateTime.Parse()应该可以很好地处理这种字符串格式。
http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240
是否为您抛出了FormatException?
ne5o7dgx5#
使用如下代码将人类可读字符串的值放入.NET DateTime:
eagi6jfj6#
也可以使用XmlConvert.ToDateString
最好指定日期种类,代码为:
有关不同解析选项http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html的更多详细信息
jum4pzuy7#
简单而直接的答案--〉
gv8xihay8#
请尝试以下代码
nzkunb0c9#
DateTime.ParseExact(DateTime,Format,DateTimeFormatInfo.InvariantInfo,DateTimeStyles.AllowLeadingWhite|DateTimeStyles.AllowTrailingWhite)
例如:
DateTime.ParseExact(“2011-03-21 13:26”,“yyyy-MM-dd hh:mm”,DateTimeFormatInfo.InvariantInfo,DateTimeStyles.AllowLeadingWhite|DateTimeStyles.AllowTrailingWhite);