How .NET reads a format string
.NET treats a format string of one character as a standard format: d is the culture's short date pattern, the same way N stands for a number with group separators. Anything longer is a custom format, read one specifier at a time, so a lone custom specifier needs a % prefix to keep it from being read as the standard one: %d is just the day of the month, while d by itself means the whole short date.
Every value on this page runs against .NET 8 itself, across tens of thousands of formats and cultures, and the culture data behind it (month names, separators, currency patterns) comes straight from .NET rather than being typed in by hand.
Date and time: the mistakes everyone makes
mmis minutes,MMis the month.yyyy-mm-ddprints the minutes in the middle of your date.hhis the 12-hour clock. Withoutttyou cannot tell 01:00 from 13:00. UseHH./and:belong to the culture.dd/MM/yyyyprints09.03.2024in de-DE. Quote them ('/') or use the invariant culture for machine-readable output.- Specifiers are case-sensitive.
YYYYandDDare not specifiers; they are copied into the output as-is. zon a DateTime is not the value's offset. It is the offset of the machine running the code. Use DateTimeOffset when the offset matters.- Use
ofor round-tripping. It is ISO 8601, invariant, keeps all seven fraction digits and the Kind or offset.
Parsing with the same format
The format string that writes a date also reads it back. DateTime.TryParseExact("2024-03-09", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date) returns true; any difference between the text and the format makes it return false. For text you did not write yourself, see String was not recognized as a valid DateTime.
In string interpolation
The same specifiers work after a colon inside an interpolated string or string.Format: $"{date:yyyy-MM-dd HH:mm}". Interpolation uses the current culture; pass one with string.Create(CultureInfo.InvariantCulture, $"...") or FormattableString.Invariant($"...").
FAQ
How do I format a DateTime as yyyy-MM-dd in C#?
date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), or $"{date:yyyy-MM-dd}" in an interpolated string. Pass the invariant culture when the text is for machines, such as file names, logs or APIs.
Why does dd/MM/yyyy print dots instead of slashes?
In a .NET date format, / is the date separator of the culture, not a literal slash. In de-DE it becomes a dot. Write '/' or \/ for a literal slash, or format with CultureInfo.InvariantCulture.
Why does a single letter like K or d behave differently?
A one-character format is always a standard format. d is the short date pattern, and K is not a standard format, so it throws a FormatException. Prefix a single custom specifier with %: %d is the day of the month and %K the time zone.
Will I get the same output on my server?
Only if you pass the culture. Without it, ToString and string interpolation use the current culture of the thread, which differs between machines and containers (and is the invariant culture in globalization-invariant mode). Culture data also comes from ICU, so small details can change between .NET and ICU versions.
What is the difference between yyyy and YYYY?
yyyy is the year. YYYY is not a .NET specifier, so the letters are copied as they are: ToString("YYYY-MM-DD") prints YYYY-03-DD.