Question

Convert a String to DateTime in C# with ParseExact

csharpstringdatetimetype-conversion

Question

How can I convert a string in the format 2009-05-08 14:40:52,531 into a C# DateTime value?

Short Answer

You will learn how C# date and time format strings work, why locale settings can affect parsing, and how to safely convert a known date format using DateTime.ParseExact or DateTime.TryParseExact.

Concept

A date stored as text is a string; it cannot be reliably compared, sorted, or used for date calculations until it is converted to a date/time type such as DateTime.

The input 2009-05-08 14:40:52,531 follows this structure:

  • 2009 — four-digit year
  • 05 — two-digit month
  • 08 — two-digit day
  • 14 — hour in 24-hour time
  • 40 — minutes
  • 52 — seconds
  • 531 — milliseconds

Because the format is known exactly, use DateTime.ParseExact or DateTime.TryParseExact. They require the input to match a format pattern, which avoids guessing based on the computer's regional settings.

For this input, the format is yyyy-MM-dd HH:mm:ss,fff.

Mental Model

Think of a format string as a labeled template for reading a date.

Input:    2009-05-08 14:40:52,531
Template: yyyy-MM-dd HH:mm:ss,fff

Each placeholder tells C# what a part of the text means. yyyy means “read four digits as a year,” while fff means “read three digits as milliseconds.” If the text does not fit the template, exact parsing fails rather than silently interpreting it incorrectly.

Take Quiz

Syntax and Examples

Use DateTime.ParseExact when invalid input should immediately produce an error.

using System;
using System.Globalization;

string input = "2009-05-08 14:40:52,531";

DateTime dateTime = DateTime.ParseExact(
    input,
    "yyyy-MM-dd HH:mm:ss,fff",
    CultureInfo.InvariantCulture
);

Console.WriteLine(dateTime);
// 05/08/2009 14:40:52
Console.WriteLine(dateTime.Millisecond);
// 531

CultureInfo.InvariantCulture makes parsing independent of the machine's language and regional settings. This is useful when the string comes from a file, API, log, or database format controlled by your application.

For user input or other data that may be invalid, prefer DateTime.TryParseExact:

using System;
using System.Globalization;

string input = "2009-05-08 14:40:52,531";

bool parsed = DateTime.TryParseExact(
    input,
    "yyyy-MM-dd HH:mm:ss,fff",
    CultureInfo.InvariantCulture,
    DateTimeStyles.None,
    out DateTime dateTime
);

if (parsed)
{
    Console.WriteLine(dateTime.ToString("O"));
}
else
{
    Console.WriteLine("The date has an invalid format.");
}

TryParseExact returns true or false instead of throwing a FormatException for invalid input.

Step by Step Execution

Consider this code:

using System;
using System.Globalization;

string input = "2009-05-08 14:40:52,531";
DateTime value = DateTime.ParseExact(
    input,
    "yyyy-MM-dd HH:mm:ss,fff",
    CultureInfo.InvariantCulture
);

C# processes the pattern as follows:

  1. yyyy reads 2009 as the year.
  2. The first - must match the hyphen in the input.
  3. MM reads 05 as the month, May.
  4. dd reads 08 as the day.
  5. HH reads 14 as a 24-hour clock value.
  6. mm reads 40 as minutes.
  7. ss reads 52 as seconds.
  8. The comma must match the comma in the input.
  9. fff reads 531 as milliseconds.

The resulting DateTime represents May 8, 2009, at 14:40:52.531. It has no time-zone information unless the input or parsing options provide it.

Real World Use Cases

Exact date parsing is common when reading structured text from systems outside your code:

  • Application logs: Parse timestamps before filtering events by time.
  • CSV imports: Convert exported date columns into values that can be validated and stored.
  • APIs: Read date fields supplied in a documented custom format.
  • Scheduled tasks: Interpret configuration values such as start times.
  • Data migrations: Convert legacy text-based date columns into proper database date/time values.

After conversion, you can safely perform operations such as dateTime.AddDays(7), compare two dates, or format the value for display.

Take Quiz

Real Codebase Usage

In production code, use TryParseExact at trust boundaries: user forms, uploaded files, API requests, and third-party data. It lets the program reject invalid data without using exceptions for ordinary validation.

A common validation pattern is:

using System;
using System.Globalization;

public static bool TryReadLogTimestamp(string text, out DateTime timestamp)
{
    const string format = "yyyy-MM-dd HH:mm:ss,fff";

    return DateTime.TryParseExact(
        text,
        format,
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out timestamp
    );
}

For systems that exchange moments across time zones, include an offset in the incoming text and use DateTimeOffset instead. For example, an ISO 8601 value such as 2009-05-08T14:40:52.531+00:00 contains enough information to identify an actual moment in time.

Common Mistakes

Using lowercase mm for the month

Lowercase mm means minutes, not months.

// Incorrect: mm means minutes
"yyyy-mm-dd HH:mm:ss,fff"

// Correct: MM means month
"yyyy-MM-dd HH:mm:ss,fff"

Using hh for a 24-hour value

hh is the 12-hour clock format and normally needs an AM/PM designator such as tt. The input uses 14, so use HH.

// Incorrect for 14:40
"yyyy-MM-dd hh:mm:ss,fff"

// Correct
"yyyy-MM-dd HH:mm:ss,fff"

Forgetting that punctuation must match

The input contains a comma before milliseconds. A format with a period does not exactly match it.

// Does not match the sample input
"yyyy-MM-dd HH:mm:ss.fff"

// Matches the sample input
"yyyy-MM-dd HH:mm:ss,fff"

Using ParseExact with untrusted input

ParseExact throws a FormatException if the text is invalid. Use TryParseExact when invalid input is expected and should be handled normally.

Assuming the result is UTC

The sample has no Z suffix or numeric offset such as +02:00. Therefore, it does not state a time zone. Do not label it UTC unless your data contract explicitly says it is UTC.

Comparisons

ApproachBest useInvalid input behaviorFormat control
DateTime.ParseFlexible, culture-aware inputThrows exceptionC# and the current/supplied culture may infer the format
DateTime.TryParseFlexible input that may be invalidReturns falseC# and culture infer the format
DateTime.ParseExactTrusted input with one known formatThrows exceptionStrict, supplied format
DateTime.TryParseExactValidation of one known formatReturns falseStrict, supplied format
DateTimeOffset.TryParseExactInput includes a UTC offsetReturns falseStrict format and offset-aware result

For a fixed machine-readable string like 2009-05-08 14:40:52,531, TryParseExact is usually the safest default.

Take Quiz

Cheat Sheet

using System;
using System.Globalization;

const string format = "yyyy-MM-dd HH:mm:ss,fff";
string input = "2009-05-08 14:40:52,531";

DateTime value = DateTime.ParseExact(
    input, format, CultureInfo.InvariantCulture
);

bool success = DateTime.TryParseExact(
    input,
    format,
    CultureInfo.InvariantCulture,
    DateTimeStyles.None,
    out DateTime value
);
TokenMeaning
yyyyFour-digit year
MMTwo-digit month
ddTwo-digit day
HHHour, 00–23
mmMinutes
ssSeconds
fffThree-digit milliseconds
  • Literal characters, including -, spaces, :, and ,, must match the input.
  • Use InvariantCulture for stable machine-generated formats.
  • Use TryParseExact when the string might be invalid.
  • A DateTime parsed from text without an offset does not inherently identify UTC or a time zone.

FAQ

What format string parses 2009-05-08 14:40:52,531 in C#?

Use "yyyy-MM-dd HH:mm:ss,fff".

Why is the month written as MM rather than mm?

In .NET custom date and time formats, uppercase MM means month. Lowercase mm means minutes.

Should I use ParseExact or TryParseExact?

Use ParseExact for trusted data that must be valid. Use TryParseExact for user input, files, or external data that can be malformed.

Does the comma before 531 depend on the current culture?

In an exact format, the comma is a literal character that must match the input. InvariantCulture keeps the rest of the parsing behavior stable.

Does this input represent local time or UTC?

It does not say. There is no offset or Z marker, so the string alone does not provide time-zone information.

How do I parse a date with a period before milliseconds?

Change the literal punctuation in the format:

"yyyy-MM-dd HH:mm:ss.fff"

What happens if milliseconds are missing?

The exact pattern with ,fff will fail. Use a second accepted format or normalize the input first.

Take Quiz

Mini Project

Description

Build a small log timestamp reader. A log file may contain valid timestamps as well as malformed lines, so the program must parse known-format values without crashing.

Goal

Read several timestamp strings and report which ones are valid using DateTime.TryParseExact.

Requirements

Use the format yyyy-MM-dd HH:mm:ss,fff.

Use CultureInfo.InvariantCulture.

Store at least four timestamp strings, including one invalid value.

Print a normalized date for valid values.

Print a clear error message for invalid values.

Take Quiz

Keep learning

Related questions

View more