Hoo*_*och 157 .net c# string datetime parsing
我有一个字符串格式的日期和时间:
"2011-03-21 13:26" //year-month-day hour:minute
Run Code Online (Sandbox Code Playgroud)
我怎么解析它System.DateTime?
我想使用类似DateTime.Parse()或DateTime.ParseExact()尽可能的函数,以便能够手动指定日期的格式.
Mit*_*eat 254
DateTime.Parse()将尝试找出给定日期的格式,它通常做得很好.如果您可以保证日期始终采用给定格式,那么您可以使用ParseExact():
string s = "2011-03-21 13:26";
DateTime dt =
DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
Run Code Online (Sandbox Code Playgroud)
(但请注意,如果日期不是预期的格式,使用其中一种TryParse方法通常会更安全)
确保在构造格式字符串时检查 自定义日期和时间格式字符串,尤其要注意字母和大小写的数量(即"MM"和"mm"表示非常不同的东西).
C#格式字符串的另一个有用资源是C#中的字符串格式化
Mat*_*att 43
正如我稍后解释的那样,我总是喜欢TryParse和TryParseExact方法.因为它们使用起来有点笨重,所以我编写了一个扩展方法,使解析更容易:
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
Run Code Online (Sandbox Code Playgroud)
与之不同Parse,ParseExact它不会抛出异常,并允许您检查通过
if (dt.HasValue) { // continue processing } else { // do error handling }
转换是否成功(在这种情况下dt有一个你可以访问的值dt.Value)或不是(在这种情况下,它是null).
这甚至允许使用像"Elvis"-operator这样的优雅快捷方式?.,例如:
int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;
Run Code Online (Sandbox Code Playgroud)
在这里你也可以year.HasValue用来检查转换是否成功,如果它没有成功那么year将包含null,否则是日期的年份部分.如果转换失败,则不会抛出异常.
解决方案: .ToDate()扩展方法
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;
}
}
Run Code Online (Sandbox Code Playgroud)
有关代码的一些信息
您可能想知道,为什么我使用了InvariantCulture调用TryParseExact:这是强制函数始终以相同的方式处理格式模式(否则例如"."可以解释为英文的小数分隔符,而它是一个组分隔符或日期分隔符德语).回想一下,我们已经在几行之前查询了基于文化的格式字符串,所以这里没问题.
更新:( .ToDate()不带参数)现在默认为线程当前文化的所有常见日期/时间模式.
请注意,我们需要result和dt一起,因为TryParseExact不允许使用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;
Run Code Online (Sandbox Code Playgroud)
或者,如果你喜欢它甚至更短:
// 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?;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你不需要两个声明DateTime? result = null;,并DateTime dt;在所有的-你可以在一行代码做到这一点.(如果您愿意,也可以写,out DateTime dt而不是写out var 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!");
}
Run Code Online (Sandbox Code Playgroud)
如您所见,此示例仅查询dt.HasValue转换是否成功.作为额外的奖励,TryParseExact允许指定strict,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);
Run Code Online (Sandbox Code Playgroud)
如果您只有几个模板模式,您还可以写:
var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
Run Code Online (Sandbox Code Playgroud)
高级示例
您可以使用??运算符默认为故障安全格式,例如
var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");
Run Code Online (Sandbox Code Playgroud)
在这种情况下,.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();
Run Code Online (Sandbox Code Playgroud)
它将使用模式动态转换数组中的日期并将其转储到控制台.
关于TryParseExact的一些背景知识
最后,这里有一些关于背景的评论(即我之所以这样写的原因):
我更倾向于在这个扩展方法中使用TryParseExact,因为你避免了异常处理 - 你可以在Eric Lippert的文章中读到关于为什么你应该使用TryParse而不是Parse的异常,我引用他关于那个主题:2)
这个 不幸的设计决定1) [注释:让Parse方法抛出一个异常]是如此令人烦恼,当然 框架团队很快就实现了TryParse, 这是正确的.
确实如此,但TryParse和TryParseExact两者还是有很多不足,使用舒适:他们强迫你使用一个未初始化的变量作为out,绝不能可为空并且当你转换,你需要评估布尔返回值参数-要么你有if立即使用一个语句,或者你必须将返回值存储在一个额外的布尔变量中,以便以后能够进行检查.并且您不能仅在不知道转换是否成功的情况下使用目标变量.
在大多数情况下,您只是想知道转换是否成功(当然还有成功的价值),因此可保留所有信息的可空目标变量将是可取的并且更加优雅 - 因为整个信息都是只存储在一个地方:这是一致的,易于使用,更不容易出错.
我编写的扩展方法正是这样做的(它还向您展示了如果您不打算使用它,每次都必须编写哪种代码).
我相信它的好处.ToDate(strDateFormat)是它看起来很简单和干净 - 就像原版本DateTime.Parse应该一样简单- 但能够检查转换是否成功,并且没有抛出异常.
1)这里的意思是异常处理(即try { ... } catch(Exception ex) { ...}块) - 当你使用Parse时它是必需的,因为如果解析了无效的字符串会抛出异常 - 在这种情况下不仅是不必要的,而且也很烦人,使您的代码复杂化.TryParse避免了所有这些,因为我提供的代码示例正在显示.
2) Eric Lippert是着名的StackOverflow研究员,并在Microsoft担任C#编译器团队的主要开发人员几年.
Rob*_*Rob 13
var dateStr = @"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);
Run Code Online (Sandbox Code Playgroud)
查看此链接以获取其他格式字符串!
DateTime.Parse()应该适用于该字符串格式.参考:
http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240
它为你抛出一个FormatException吗?
使用如下代码将人类可读字符串的值放入 .NET DateTime 中:
DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
261880 次 |
| 最近记录: |