226

I have date and time in a string formatted like that one:

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

How can I parse it to System.DateTime?

I want to use functions like DateTime.Parse() or DateTime.ParseExact() if possible, to be able to specify the format of the date manually.

Matt
  • 25,467
  • 18
  • 120
  • 187
Hooch
  • 28,817
  • 29
  • 102
  • 161
  • 21
    So why don't you use DateTime.Parse? – Austin Salonen Mar 20 '11 at 02:06
  • 9
    I was one of the downvoters. It was because your original question (http://stackoverflow.com/revisions/3c6789f2-8a6b-4557-bafc-1b8eb4d5f8c4/view-source) stated that you WANTED to use DateTime.Parse() but you didn't state WHY you couldn't use it. This made it seem like a nonsense question, especially since a simple check would have made it clear that cacois's was correct: Your string "2011-03-21 13:26" is not a problem for DateTime.Parse(). Finally, you did not make any mention of ParseExact() in your original question. You waited until *after* Mitch's answer to add this in an edit. – anon Mar 20 '11 at 04:31
  • 9
    I just love those people down-voting question without giving any reason in comments. – Hooch Apr 21 '15 at 11:46

9 Answers9

364

DateTime.Parse() will try figure out the format of the given date, and it usually does a good job. If you can guarantee dates will always be in a given format then you can use ParseExact():

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

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

(But note that it is usually safer to use one of the TryParse methods in case a date is not in the expected format)

Make sure to check Custom Date and Time Format Strings when constructing format string, especially pay attention to number of letters and case (i.e. "MM" and "mm" mean very different things).

Another useful resource for C# format strings is String Formatting in C#

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
  • 5
    Correction - it is ALWAYS safer ;) If you are calling a method with an exception, always check the exception condition first if possible. – Gusdor Aug 27 '13 at 12:36
  • 3
    I'd say it's safer to always pass your culture. I'd rather have an exception than having "01-02-2013" be misinterpreted as either the second of January or the first of February. – Carra Oct 14 '13 at 08:38
  • 1
    @Carra: dates in ISO8601 format (i.e. yyyy-mm-dd' are always interpreted the correct way. That';s why we use ISO8601 format dates... – Mitch Wheat Jul 16 '14 at 02:41
  • 1
    Parse exact can be useful. Sometimes, I would prefer my application crash and my computer light on fire, as opposed to producing incorrect output. Depends on the application. – Allen Jul 31 '15 at 18:03
  • **ParseExact** is great because it is flexible, but it has a downside: Note that ParseExact and Parse methods throw exceptions if there is a syntax error in the date format of variable `s`. Hence, it is better to use **TryParseExcact.** I have pointed out why in my answer below. – Matt Sep 04 '15 at 13:11
  • quoting from my answer : "(But note that it is usually safer to use one of the TryParse methods in case a date is not in the expected format)" – Mitch Wheat Sep 04 '15 at 13:22
  • You are right and I am sorry, I overlooked that. But I think the extension method I suggested is a useful addition to your answer. – Matt Sep 04 '15 at 17:14
65

As I am explaining later, I would always favor the TryParse and TryParseExact methods. Because they are a bit bulky to use, I have written an extension method which makes parsing much easier:

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

Or more simply, if you want to use the date patterns of your current culture implicitly, you can use it like:

 DateTime? dt = dtStr.ToDate();

In that case no specific pattern need to be specified. If it is not specified, then the default DateTime pattern of the current culture (in the current thread) is used.

Unlike Parse, ParseExact etc. it does not throw an exception, and allows you to check via

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

whether the conversion was successful (in this case dt has a value you can access via dt.Value) or not (in this case, it is null).

That even allows to use elegant shortcuts like the "Elvis"-operator ?., for example:

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

Here you can also use year.HasValue to check if the conversion succeeded, and if it did not succeed then year will contain null, otherwise the year portion of the date. There is no exception thrown if the conversion failed.


Solution:  The   .ToDate()   extension method

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

Some information about the code

You might wonder, why I have used InvariantCulture calling TryParseExact: This is to force the function to treat format patterns always the same way (otherwise for example "." could be interpreted as decimal separator in English while it is a group separator or a date separator in German). Recall we have already queried the culture based format strings a few lines before so that is okay here.

Update: .ToDate() (without parameters) now defaults to all common date/time patterns of the thread's current culture.
Note that we need the result and dt together, because TryParseExact does not allow to use DateTime?, which we intend to return. In C# Version 7 you could simplify the ToDate function a bit as follows:

 // in C#7 only: "DateTime dt;" - no longer required, declare implicitly
 if (DateTime.TryParseExact(dateTimeStr, dateFmt,
     CultureInfo.InvariantCulture, style, out var dt)) result = dt;

or, if you like it even shorter:

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

in which case you don't need the two declarations DateTime? result = null; and DateTime dt; at all - you can do it in one line of code. (It would also be allowed to write out DateTime dt instead of out var dt if you prefer that).

The old style of C# would have required it the following way (I removed that from the code above):

  // DateTime? result = null;
  // DateTime dt;
  // if (DateTime.TryParseExact(dateTimeStr, dateFmt,
  //    CultureInfo.InvariantCulture, style, out dt)) result = dt;

I have simplified the code further by using the params keyword: Now you don't need the 2nd overloaded method any more.


Example of usage

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

As you can see, this example just queries dt.HasValue to see if the conversion was successful or not. As an extra bonus, TryParseExact allows to specify strict DateTimeStyles so you know exactly whether a proper date/time string has been passed or not.


More Examples of usage

The overloaded function allows you to pass an array of valid formats used for parsing/converting dates as shown here as well (TryParseExact directly supports this), e.g.

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

If you have only a few template patterns, you can also write:

var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");

Advanced examples

You can use the ?? operator to default to a fail-safe format, e.g.

var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");

In this case, the .ToDate() would use common local culture date formats, and if all these failed, it would try to use the ISO standard format "yyyy-MM-dd HH:mm:ss" as a fallback. This way, the extension function allows to "chain" different fallback formats easily.

You can even use the extension in LINQ, try this out (it's in the .NetFiddle above):

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

which will convert the dates in the array on the fly by using the patterns and dump them to the console.


Some background about TryParseExact

Finally, Here are some comments about the background (i.e. the reason why I have written it this way):

I am preferring TryParseExact in this extension method, because you avoid exception handling - you can read in Eric Lippert's article about exceptions3) why you should use TryParse rather than Parse, I quote him about that topic:2)

This unfortunate design decision1) [annotation: to let the Parse method throw an exception] was so vexing that of course the frameworks team implemented TryParse shortly thereafter which does the right thing.

It does, but TryParse and TryParseExact both are still a lot less than comfortable to use: They force you to use an uninitialized variable as an out parameter which must not be nullable and while you're converting you need to evaluate the boolean return value - either you have to use an ifstatement immediately or you have to store the return value in an additional boolean variable so you're able to do the check later. And you can't just use the target variable without knowing if the conversion was successful or not.

In most cases you just want to know whether the conversion was successful or not (and of course the value if it was successful), so a nullable target variable which keeps all the information would be desirable and much more elegant - because the entire information is just stored in one place: That is consistent and easy to use, and much less error-prone.

The extension method I have written does exactly that (it also shows you what kind of code you would have to write every time if you're not going to use it).

I believe the benefit of .ToDate(strDateFormat) is that it looks simple and clean - as simple as the original DateTime.Parse was supposed to be - but with the ability to check if the conversion was successful, and without throwing exceptions.


1) What is meant here is that exception handling (i.e. a try { ... } catch(Exception ex) { ...} block) - which is necessary when you're using Parse because it will throw an exception if an invalid string is parsed - is not only unnecessary in this case but also annoying, and complicating your code. TryParse avoids all this as the code sample I've provided is showing.


2) Eric Lippert is a famous StackOverflow fellow and was working at Microsoft as principal developer on the C# compiler team for a couple of years.

3) Unfortunately, Microsoft has removed this article from their MSDN site. If someone finds it on a different URL, please let me know and I'll update it.

Matt
  • 25,467
  • 18
  • 120
  • 187
  • what if I need to parse a date in the format if "dd/MM/yyyy" and then also parse a date in the format of "MM/dd/yyyy"? so for example, I have a date "07/09/2021" I need to be able to parse it correctly. B-) – James Sep 22 '21 at 18:48
  • In this case, your date is ambiguous and none of the parse functions are able to predict what you mean: 7th September or 9th July 2021 ? The only way in this case is to let the user choose which culture he/she wants to use and then apply the right pattern. Or you use a pattern where the user has to specify the month like "September" or "July", i.e. "dd/MMMM/yyyy". @James – Matt Sep 23 '21 at 06:31
17
var dateStr = @"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);

Check out this link for other format strings!

DatRid
  • 1,169
  • 2
  • 21
  • 46
Rob
  • 26,989
  • 16
  • 82
  • 98
5

DateTime.Parse() should work fine for that string format. Reference:

http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240

Is it throwing a FormatException for you?

cacois
  • 2,036
  • 2
  • 19
  • 19
5

Put the value of a human-readable string into a .NET DateTime with code like this:

DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
Zack Peterson
  • 56,055
  • 78
  • 209
  • 280
3

You can also use XmlConvert.ToDateString

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

It is good to specify the date kind, the code is:

var anotherParsedDate = DateTime.ParseExact(dateStr, "yyyy-MM-dd hh:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

More details on different parsing options http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html

Andrea Perelli
  • 156
  • 2
  • 3
  • 14
Amir Shenouda
  • 2,135
  • 1
  • 13
  • 6
2

The simple and straightforward answer -->

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.
 * */
Shivam Bharadwaj
  • 1,864
  • 21
  • 23
0

Try the following code

Month = Date = DateTime.Now.Month.ToString();   
Year = DateTime.Now.Year.ToString(); 
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;
Ali
  • 2,702
  • 3
  • 32
  • 54
  • 1
    Hi, Welcome, Please provide an explanation when answering a question. Just posting code is not recommended – Ali Jan 24 '19 at 07:27
  • Though GetMonthName is a useful method, it is not how this should be done in .NET -- all of the date string formatting options have been provided by the framework for this purpose. You can even provide your own format. This approach should be viewed as an unnecessary hack, if a DateTime or DateTimeOffset object is available. – ryanwebjackson Sep 09 '21 at 21:24
-1

DateTime.ParseExact(DateTime, Format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite)

for example:

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