.net 在C#中将字符串解析为DateTime

dhxwm5r4  于 2023-04-22  发布在  .NET
关注(0)|答案(9)|浏览(110)

我有日期和时间在一个字符串格式如下:

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

如何将其解析为System.DateTime
如果可能的话,我想使用像DateTime.Parse()DateTime.ParseExact()这样的函数,以便能够手动指定日期的格式。

7rfyedvj

7rfyedvj1#

DateTime.Parse()将尝试找出给定日期的格式,它通常做得很好。如果你可以保证日期总是给定的格式,那么你可以使用ParseExact()

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

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

(But注意,如果日期不是预期的格式,通常使用TryParse方法之一更安全)
在构造格式字符串时,一定要检查Custom Date and Time Format Strings,特别要注意字母的数量和大小写(即“MM”和“mm”的含义非常不同)。
另一个有用的C#格式字符串资源是String Formatting in C#

2wnc66cl

2wnc66cl2#

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

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

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

DateTime? dt = dtStr.ToDate();

在这种情况下,不需要指定特定的模式。如果未指定,则使用当前区域性(在当前线程中)的默认DateTime模式。
ParseParseExact等不同,它不会抛出异常,并允许您通过
if (dt.HasValue) { // continue processing } else { // do error handling }
转换是否成功(在本例中,dt的值可以通过dt.Value访问)(在本例中,它是null)。
这甚至允许使用优雅的快捷方式,如“Elvis”操作符?.,例如:

int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;

这里你也可以使用year.HasValue来检查转换是否成功,如果没有成功,那么year将包含null,否则是日期的年份部分。如果转换失败,不会抛出异常。

解决方案:** .ToDate() 扩展方法**
Try it in .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?,我们打算返回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!");
}

正如你所看到的,这个例子只是查询dt.HasValue来查看转换是否成功。作为一个额外的好处,TryParseExact允许指定严格的DateTimeStyles,这样你就可以确切地知道是否传递了正确的日期/时间字符串。

更多用法示例

重载函数允许你传递一个有效格式数组,用于解析/转换日期,如here所示(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 standard"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,因为你避免了异常处理-你可以read in Eric Lippert's article about exceptions 3)为什么你应该使用TryParse而不是Parse,我引用他关于这个主题的话:2)
这个不幸的设计决定1)[注解:让Parse方法抛出异常]是如此令人烦恼,当然框架团队随后不久就实现了TryParse,它做了正确的事情。
确实如此,但是TryParseTryParseExact使用起来还是不太舒服:它们强迫你使用一个未初始化的变量作为out参数,这个参数不能为空,并且在转换时你需要计算布尔返回值--要么你必须立即使用一个if语句,要么你必须将返回值存储在一个额外的布尔变量中,这样你就可以在以后进行检查。在不知道转换是否成功的情况下,不要只使用目标变量。
在大多数情况下,你只想知道 * 转换是否成功(当然,如果成功了,还需要知道值)*,所以一个可空的目标变量将保留所有信息,这将是可取的,而且更优雅-因为整个信息只是存储在一个地方:这是一致的,易于使用,而且更不容易出错。

我所编写的扩展方法正是这样做的(它还向您展示了如果您不打算使用它,每次都必须编写什么样的代码)。
我相信.ToDate(strDateFormat)的好处是它看起来简单而干净--就像最初的DateTime.Parse一样简单--但是能够检查转换是否成功,并且不会抛出异常。

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

2)Eric Lippert是著名的StackOverflow fellow,曾在微软C#编译器团队担任首席开发人员几年。
3)不幸的是,微软已经从他们的MSDN站点上删除了这篇文章。如果有人在其他URL上找到它,请让我知道,我会更新它。

yhuiod9q

yhuiod9q3#

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

查看link以获取其他格式字符串!

ddarikpa

ddarikpa4#

DateTime.Parse()应该可以很好地处理这种字符串格式。
http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240
是否为您抛出了FormatException?

ne5o7dgx

ne5o7dgx5#

使用如下代码将人类可读字符串的值放入.NET DateTime:

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

eagi6jfj6#

也可以使用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的更多详细信息

jum4pzuy

jum4pzuy7#

简单而直接的答案--〉

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.
 * */
gv8xihay

gv8xihay8#

请尝试以下代码

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

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

相关问题