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 year05— two-digit month08— two-digit day14— hour in 24-hour time40— minutes52— seconds531— 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.
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:
yyyyreads2009as the year.- The first
-must match the hyphen in the input. MMreads05as the month, May.ddreads08as the day.HHreads14as a 24-hour clock value.mmreads40as minutes.ssreads52as seconds.- The comma must match the comma in the input.
fffreads531as 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.
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
| Approach | Best use | Invalid input behavior | Format control |
|---|---|---|---|
DateTime.Parse | Flexible, culture-aware input | Throws exception | C# and the current/supplied culture may infer the format |
DateTime.TryParse | Flexible input that may be invalid | Returns false | C# and culture infer the format |
DateTime.ParseExact | Trusted input with one known format | Throws exception | Strict, supplied format |
DateTime.TryParseExact | Validation of one known format | Returns false | Strict, supplied format |
DateTimeOffset.TryParseExact | Input includes a UTC offset | Returns false | Strict 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.
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
);
| Token | Meaning |
|---|---|
yyyy | Four-digit year |
MM | Two-digit month |
dd | Two-digit day |
HH | Hour, 00–23 |
mm | Minutes |
ss | Seconds |
fff | Three-digit milliseconds |
- Literal characters, including
-, spaces,:, and,, must match the input. - Use
InvariantCulturefor stable machine-generated formats. - Use
TryParseExactwhen the string might be invalid. - A
DateTimeparsed 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.
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.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.