C# – Parsing a DateTime from a string

You can convert a string to a DateTime (parse) with one of these methods:

  • DateTime.Parse() (or TryParse). Use this to parse a variety of standard formats (culture-specific or ISO-8601)
  • DateTime.ParseExact() (or TryParseExact). Use this to parse from a specific format.

I’ll show examples of using both methods for parsing various DateTime formats.

Using DateTime.Parse()

DateTime.Parse() can handle parsing a wide variety of culture-specific standard DateTime formats and the ISO-8601 format (which is the default date format for JSON serialization). By default, it uses the current culture. If there’s partial information (such as just the date), it makes assumptions and fills in information.

Here’s an example of using DateTime.Parse() to parse several standard DateTime formats:

// Culture-specific standard formats
// Note: This is using my current culture (en-US) with date format: M/d/yyyy h:mm:ss AM|PM

var dateAndTime = DateTime.Parse("5/3/2023 8:15:10 AM");
Console.WriteLine(dateAndTime); 
//Outputs: 5/3/2023 8:15:10 AM

var longDate = DateTime.Parse("Wednesday, May 3, 2023");
Console.WriteLine(longDate); 
//Outputs: 5/3/2023 12:00:00 AM (it assumes 12:00)

var dateOnly = DateTime.Parse("5/3/2023");
Console.WriteLine(dateOnly); 
//Outputs: 5/3/2023 12:00:00 AM (it assumes 12:00)

var timeOnly = DateTime.Parse("08:15:10");
Console.WriteLine(timeOnly); 
//Outputs: 5/3/2023 8:15:10 AM (it assumes today's date)

// ISO-8601 standard format

var iso8601_withTimeZone = DateTime.Parse("2023-05-03T08:15:10.4068309-04:00");
Console.WriteLine(iso8601_withTimeZone); 
//Outputs: 5/3/2023 8:15:10 AM

var iso8601_UTC = DateTime.Parse("2023-05-03T12:15:10.4068309Z");
Console.WriteLine(iso8601_UTC); 
//Outputs: 5/3/2023 8:15:10 AM
Code language: C# (cs)

Read more about how to test that you’re able to handle other culture’s date formats.

If DateTime.Parse() can’t figure out the format automatically, it throws a FormatException. You can use DateTime.TryParse() for better error handling. Here’s an example:

if (DateTime.TryParse("050323", out DateTime result))
{
    //use result
}
else
{
    //It wasn't able to parse automatically
}
Code language: C# (cs)

Using DateTime.ParseExact()

You can use DateTime.ParseExact() to parse a specific DateTime format. Use this in two cases:

  • You want to parse a custom (non-standard) DateTime format.
  • You *only* want to parse a specific DateTime format (standard or not).

Here are examples of using DateTime.ParseExact() with different format strings:

//Note: Console.WriteLine is outputting using my current culture (en-US) format (M/d/yyyy h:mm:ss AM|PM)

//Custom formats

var dateMMddyy = DateTime.ParseExact("050323", format: "MMddyy", CultureInfo.InvariantCulture);
Console.WriteLine(dateMMddyy); 
//Outputs: 5/3/2023 12:00:00 AM (assumes 12:00 AM)

var dateyyyyMMdd = DateTime.ParseExact("20230503", format: "yyyyMMdd", CultureInfo.InvariantCulture);
Console.WriteLine(dateyyyyMMdd);
 //Outputs: 5/3/2023 12:00:00 AM (assumes 12:00 AM)

var MMddyy = DateTime.ParseExact("2023-03-05", format: "yyyy-dd-MM", CultureInfo.InvariantCulture);
Console.WriteLine(MMddyy); 
//Outputs: 5/3/2023 12:00:00 AM (assumes 12:00 AM)

//ISO-8601 formats

var iso8601_WithTimeZone = "2023-05-03T08:15:10.4068309-04:00";
var dateISO8601 = DateTime.ParseExact(iso8601_WithTimeZone, format: "O", CultureInfo.InvariantCulture);
Console.WriteLine(dateISO8601); 
//Outputs: 5/3/2023 8:15:10 AM

var iso8601_UTC = "2023-05-03T12:15:10.4068309Z";
var dateUTC = DateTime.ParseExact(iso8601_UTC, format: "O", CultureInfo.InvariantCulture);
Console.WriteLine(dateUTC); 
//Outputs: 5/3/2023 8:15:10 AM
Code language: C# (cs)

Note: This overload of ParseExact() uses DateTimeStyles.None internally, so you don’t need to pass that in.

If DateTime.ParseExact() can’t parse to the exact DateTime format you specified, it throws a FormatException. Use DateTime.TryParseExact() for better error handling. Here’s an example:

if (DateTime.TryParseExact(dateString, format: "MMddyy", 
    CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result))
{
    //use result
}
else
{
    //It wasn't able to parse automatically
}
Code language: C# (cs)

DateTime format specifiers

When you’re using DateTime.ParseExact(), you pass it a format string. These are the same format strings you use when converting a DateTime to a string. This consists of a combination of format specifier characters (such as “MM”, “yyyy”) or a single character (such as “o”). Here’s a quick reference table for common formats:

Format specifierDescriptionExample
dd/MM/yyyyday of month (2 digits), month (2 digits), year (4 digits)03/05/2023 (May 3rd, 2023)
M/d/yyyymonth (1-2 digits), day (1-2 digits), year (4 digits)5/3/2023 (May 3rd, 2023)
12/25/2023 (December 25th, 2023)
yyyy-MM-ddyear (4 digits), month (2 digits), day (2 digits)2023-05-03 (May 3rd, 2023)
yyyyMMddyear (4 digits), month (2 digits), day (2 digits)20230503 (May 3rd, 2023)
HH:mm24-hour time14:15 (2:15 pm)
oISO-8601 format2023-05-03T12:15:10.4068309Z

In Visual Studio, when you start typing in the format string, IntelliSense pops up a full list of individual format specifier characters you can use. In addition, if you want an exhaustive list, check out this MSDN page about all of the possible format specifiers.

Parsing a two-digit year

We all know it’s a bad idea to use two-digit years. When you use a two-digit year, you lose information and have to guess what four-digit year it represents.

When you parse a two-digit year with DateTime.ParseExact(), it uses CultureInfo.Calendar.TwoDigitYearMax to determine how to parse it into a four-digit year. The default TwoDigitYearMax on my system right now is 2049. You can pass in a CultureInfo and set TwoDigitYearMax to whatever value makes sense in your scenario.

Here’s an example. Let’s say I need to parse “9912” into “yyMM” and I know I’m dealing with future dates in the current century. If I let it use the default TwoDigitYearMax, it will parse this into “12/1/1999”. I really want it to parse into “12/1/2099”, so I need to set TwoDigitYearMax=2100, like this:

string date = "9912";

CultureInfo culture = new CultureInfo("en-US");
culture.Calendar.TwoDigitYearMax = 2100;

if (DateTime.TryParseExact(date, "yyMM", culture, DateTimeStyles.None, out DateTime dt))
{
	Console.WriteLine($"Parsed {date} into {dt}");
}
else
{
	Console.WriteLine($"Unable to parse {date}");
}
Code language: C# (cs)

This output the following:

Parsed 9912 into 12/1/2099 12:00:00 AMCode language: plaintext (plaintext)

The current year is 2023. What if I want to assume the two-digit year always starts at the current year? I can set TwoDigitYearMax to the current year (from DateTime.Now.Year) + 99, like this:

string date = "2112";

CultureInfo culture = new CultureInfo("en-US");
culture.Calendar.TwoDigitYearMax = DateTime.Now.Year + 99;

if (DateTime.TryParseExact(date, "yyMM", culture, DateTimeStyles.None, out DateTime dt))
{
	Console.WriteLine($"Parsed {date} into {dt}");
}
else
{
	Console.WriteLine($"Unable to parse {date}");
}
Code language: C# (cs)

This output the following:

Parsed 2112 into 11/1/2023 12:00:00 AMCode language: plaintext (plaintext)

Dealing with uncertainty with a two-digit year

In the examples above I mentioned that I knew I was dealing with future dates. What if you’re dealing with dates that could be in either the future or past, or have more than a 100 year range?

I can think of two examples:

  • Birthdates
  • Expiration dates

If you were parsing data with birthdates that had two-digit years, you won’t be able to say with 100% certainty that you’re going to guess the correct four-digit year.

For example, let’s say you get the birthdate: “1/1/19”. Logically, all birthdates will be in the past, so you could set the TwoDigitYearMax = the current year of 2021. But this birthdate could realistically be either “1/1/1999” or “1/1/1919”, since there are definitely people who are over 100 years old.

How would you deal with this? My recommendation would be, whenever there is uncertainty involved, have a person double-check the results and confirm the year. This is the problem with two-digit years – there is always a chance you guessed the wrong year.