繁体   English   中英

将字符串解析为 C# 中的 DateTime

[英]Parse string to DateTime in C#

我的日期和时间格式如下:

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

如何将其解析为System.DateTime

如果可能,我想使用DateTime.Parse()DateTime.ParseExact()之类的函数,以便能够手动指定日期的格式。

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# 格式字符串的另一个有用资源是 C# 中的字符串格式

正如我稍后解释的那样,我总是喜欢TryParseTryParseExact方法。 因为它们使用起来有点笨重,我编写了一个扩展方法,使解析更容易:

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

或者更简单地说,如果你想隐式地使用当前文化的日期模式,你可以像这样使用它:

 DateTime? dt = dtStr.ToDate();

在这种情况下,不需要指定特定的模式。

ParseParseExact等不同,它不会抛出异常,并允许您通过

if (dt.HasValue) { // continue processing } else { // do error handling }

转换是否成功(在这种情况下dt有一个您可以通过dt.Value访问的值)或dt.Value (在这种情况下,它是null )。

这甚至允许使用优雅的快捷方式,如“Elvis”-operator ?. , 例如:

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? <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;
  }
}

关于代码的一些信息

您可能想知道,为什么我使用InvariantCulture调用TryParseExact :这是为了强制函数始终以相同的方式处理格式模式(否则,例如“.”在英语中可以解释为小数点分隔符,而它是组分隔符日期分隔符德语)。 回想一下,我们已经在几行之前查询了基于文化的格式字符串,所以这里没问题。

更新: .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;

或者,如果你喜欢它更短:

 // 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? 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!");
}

如您所见,此示例仅查询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 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 ,因为您可以避免异常处理- 您可以阅读 Eric Lippert 的文章,了解为什么应该使用 TryParse 而不是 Parse 的异常,我引用了他关于该主题的内容: 2)

这个不幸的设计决定1) [注释:让 Parse 方法抛出异常] 非常令人烦恼,当然框架团队在此后不久就实现了 TryParse,它做了正确的事情。

确实如此,但TryParseTryParseExact使用起来仍然不太舒服:它们强制您使用未初始化的变量作为out参数,该参数不能为空,并且在转换时您需要评估布尔返回值 -要么必须立即使用if语句,要么必须将返回值存储在附加的布尔变量中,以便稍后进行检查。 并且您不能在不知道转换是否成功的情况下只使用目标变量。

在大多数情况下,您只想知道转换是否成功(当然还有成功时的值) ,因此保留所有信息的空的目标变量将是可取的且更加优雅 - 因为整个信息是只存储在一个地方:这是一致且易于使用的,而且不容易出错。

我编写的扩展方法正是这样做的(它还向您展示了如果您不打算使用它,则每次都必须编写什么样的代码)。

我相信.ToDate(strDateFormat)的好处是它看起来简单干净 - 就像原来的DateTime.Parse应该是一样简单 - 但能够检查转换是否成功,并且不会抛出异常。


1)这里的意思是异常处理(即try { ... } catch(Exception ex) { ...}块) - 当您使用 Parse 时这是必要的,因为如果无效,它将抛出异常字符串被解析 - 在这种情况下不仅是不必要的,而且很烦人,并使您的代码复杂化。 TryParse 避免了所有这些,因为我提供的代码示例正在显示。


2) Eric Lippert 是一位著名的StackOverflow 研究员,曾在 Microsoft 作为 C# 编译器团队的首席开发人员工作了几年。

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

查看此链接以获取其他格式字符串!

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

您还可以使用 XmlConvert.ToDateString

var dateStr = "2011-03-21 13:26";
var parsedDate = XmlConvert.ToDateTime(dateStr, "yyyy-MM-dd hh:mm");

最好指定日期种类,代码为:

var 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

简单明了的答案-->

using System;

namespace DemoApp.App

{
public class TestClassDate
{
    public static DateTime GetDate(string string_date)
    {
        DateTime dateValue;
        if (DateTime.TryParse(string_date, out dateValue))
            Console.WriteLine("Converted '{0}' to {1}.", string_date, dateValue);
        else
            Console.WriteLine("Unable to convert '{0}' to a date.", string_date);
        return dateValue;
    }
    public static void Main()
    {
        string inString = "05/01/2009 06:32:00";
        GetDate(inString);
    }
}
}

/**
 * Output:
 * Converted '05/01/2009 06:32:00' to 5/1/2009 6:32:00 AM.
 * */

试试下面的代码

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;

DateTime.ParseExact(日期时间,格式,DateTimeFormatInfo.InvariantInfo,DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite)

例如:

DateTime.ParseExact("2011-03-21 13:26", "yyyy-MM-dd hh:mm", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM