Question
How can I convert a C# DateTime value to a string in the yyyyMMddHHmmss format, such as 20250308143045? Is there a built-in way to produce this format?
Short Answer
You will learn how to use C# custom date and time format strings with DateTime.ToString(). You will also learn why letter casing matters, how to avoid confusing months with minutes, and when to format a time in UTC.
Concept
C# does not need a separate method for every possible date layout. Instead, DateTime.ToString() accepts a custom format string that describes exactly how the result should look.
For a compact timestamp containing year, month, day, hour, minute, and second, use:
string timestamp = dateTime.ToString("yyyyMMddHHmmss");
Each group of letters is a format specifier:
yyyy— four-digit year, such as2025MM— two-digit month, such as03dd— two-digit day, such as08HH— hour on a 24-hour clock, from00to23mm— two-digit minutess— two-digit second
Casing is important. In particular, uppercase MM means month, while lowercase mm means minute. Also, the standard .NET year specifier is lowercase yyyy, not uppercase YYYY.
Formatting creates a string; it does not change the original DateTime value. This is useful when writing timestamps to filenames, log entries, export files, or APIs that require a fixed text format.
Mental Model
Think of a format string as a template with date-time placeholders.
A DateTime is like a box containing separate values: year, month, day, hour, minute, and second. The format string tells C# which values to take from the box, in what order, and whether to add padding zeros.
yyyy MM dd HH mm ss
2025 03 08 14 30 45
Removing spaces and separators from that template produces:
20250308143045
The letter case is like using different labels for different compartments: MM selects the month compartment, while mm selects the minute compartment.
Syntax and Examples
Use ToString with a custom date and time format string:
DateTime dateTime = new DateTime(2025, 3, 8, 14, 30, 45);
string result = dateTime.ToString("yyyyMMddHHmmss");
Console.WriteLine(result); // 20250308143045
The output is always 14 characters long when the format contains these parts:
- 4 characters for the year
- 2 for month
- 2 for day
- 2 for hour
- 2 for minute
- 2 for second
For machine-readable output, explicitly use the invariant culture:
using System.Globalization;
DateTime dateTime = DateTime.Now;
string result = dateTime.ToString(
"yyyyMMddHHmmss",
CultureInfo.InvariantCulture);
For this numeric format, the output is already normally culture-independent. Still, InvariantCulture makes the intent clear and is a useful habit for stored or exchanged data.
If the timestamp represents a shared, global moment, convert to UTC first:
using System.Globalization;
string utcTimestamp = DateTime.UtcNow.ToString(
"yyyyMMddHHmmss",
CultureInfo.InvariantCulture);
Step by Step Execution
Consider this code:
DateTime createdAt = new DateTime(2025, 1, 5, 9, 7, 3);
string fileStamp = createdAt.ToString("yyyyMMddHHmmss");
Console.WriteLine(fileStamp);
Step by step:
createdAtstores January 5, 2025 at 09:07:03.yyyyreads the year and produces2025.MMreads the month and pads it to two digits:01.ddreads the day:05.HHreads the 24-hour value:09.mmreads the minute:07.ssreads the second:03.- C# joins all parts without separators, producing
20250105090703.
The original createdAt value remains a DateTime. Only fileStamp is converted to text.
Real World Use Cases
This compact format is useful where punctuation would be inconvenient or where chronological sorting matters.
- Unique-looking filenames:
report-20250308143045.csv - Application logs: Prefix a record with
20250308143045 - Data exports: Include an export creation time in a file name.
- Batch jobs: Store a run identifier such as
job-20250308143045. - API integrations: Send a timestamp when an external system specifically requires this layout.
Because the format starts with the largest time unit and ends with the smallest, timestamps sort correctly as text when they all use the same time zone:
20250308100500
20250308143045
20250309000000
For a true unique identifier, do not rely only on seconds: two operations can occur during the same second. Add milliseconds, a counter, or use a GUID when uniqueness is required.
Real Codebase Usage
In production code, developers usually decide two things before formatting: which time zone the value represents and why it is becoming a string.
Use UTC for shared system timestamps
For logs, distributed services, and data exchanged between systems, UTC avoids ambiguity caused by local time zones and daylight-saving changes.
using System.Globalization;
string auditStamp = DateTime.UtcNow.ToString(
"yyyyMMddHHmmss",
CultureInfo.InvariantCulture);
Keep dates as date-time values until output is needed
Do not convert a value to a string early and then try to compare or calculate with it. Keep a DateTime or, often, a DateTimeOffset in your application logic.
DateTime expiresAt = DateTime.UtcNow.AddHours(1);
bool hasExpired = DateTime.UtcNow >= expiresAt;
string displayValue = expiresAt.ToString("yyyyMMddHHmmss");
Make reusable formatting explicit
A helper can standardize a required external format:
using System.Globalization;
public static string ToCompactUtcTimestamp(DateTime value)
{
return value.ToUniversalTime()
.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture);
}
If the original offset matters, prefer DateTimeOffset for values received from users, APIs, or databases. It represents both a clock time and its UTC offset.
Common Mistakes
Using YYYY instead of yyyy
In .NET custom date and time formats, use lowercase yyyy for the calendar year.
// Incorrect for a C# custom date-time format
string text = dateTime.ToString("YYYYMMDDHHMMSS");
// Correct
string text = dateTime.ToString("yyyyMMddHHmmss");
Confusing month and minute
MM is month; mm is minute.
// Wrong: uses minutes where the month belongs
string text = dateTime.ToString("yyyymmddHHMMss");
// Correct
string text = dateTime.ToString("yyyyMMddHHmmss");
Using hh when a 24-hour clock is required
hh formats hours from 01 to 12. Use HH for 00 to 23.
DateTime time = new DateTime(2025, 3, 8, 18, 5, 0);
Console.WriteLine(time.ToString("hhmmss")); // 060500
Console.WriteLine(time.ToString("HHmmss")); // 180500
Assuming the formatted string includes a time zone
yyyyMMddHHmmss contains no offset or UTC marker. 20250308143045 is ambiguous unless your application documents whether it is local time or UTC.
Treating the formatted string as a date-time value
The result of ToString() is text. Keep the original DateTime for comparisons, arithmetic, and database date columns.
Assuming seconds make a filename unique
Multiple requests can happen in the same second. If needed, append milliseconds with fff or use a dedicated identifier.
Comparisons
| Format | Meaning | Example output | When to use it |
|---|---|---|---|
yyyyMMddHHmmss | 24-hour compact local or UTC timestamp | 20250308143045 | Filenames, required legacy formats |
yyyy-MM-dd HH:mm:ss | Readable date and time | 2025-03-08 14:30:45 | Logs and reports for people |
yyyy-MM-ddTHH:mm:ssZ | ISO 8601 UTC-style text | 2025-03-08T14:30:45Z | APIs and data interchange, when the value is UTC |
O | Round-trip date/time format | 2025-03-08T14:30:45.0000000Z | Precise serialization and diagnostics |
DateTime versus DateTimeOffset
| Type | Best for |
|---|---|
DateTime | A date/time when the time-zone convention is already known by the application |
DateTimeOffset | A timestamp that must preserve or communicate its UTC offset |
DateTimeOffset can also use the same custom format:
DateTimeOffset now = DateTimeOffset.UtcNow;
string stamp = now.ToString("yyyyMMddHHmmss");
Cheat Sheet
// Required compact format
string stamp = value.ToString("yyyyMMddHHmmss");
// Current UTC time, suitable for shared systems
string utcStamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
// Include milliseconds when needed
string preciseStamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
| Specifier | Output | Meaning |
|---|---|---|
yyyy | 2025 | Four-digit year |
MM | 03 | Month |
dd | 08 | Day of month |
HH | 14 | Hour, 00–23 |
hh | 02 | Hour, 01–12 |
mm | 30 | Minute |
ss | 45 | Second |
fff | 123 | Milliseconds |
Rules:
- Format specifiers are case-sensitive.
ToString()returns astring; it does not modify the date-time value.- Use UTC consistently for values shared across time zones.
- Use
CultureInfo.InvariantCulturewhen making a machine-oriented formatting policy explicit.
FAQ
Is YYYYMMDDHHMMSS the correct C# format string?
No. Use yyyyMMddHHmmss. C# custom date and time format specifiers are case-sensitive: MM is month and mm is minute.
How do I get the current timestamp in this format?
string stamp = DateTime.Now.ToString("yyyyMMddHHmmss");
Use DateTime.UtcNow instead if the timestamp should be in UTC.
Does yyyyMMddHHmmss use a 24-hour clock?
Yes. Uppercase HH produces hours from 00 through 23.
Can this format be used in filenames?
Yes. It contains only digits, so it is safe as the date portion of a filename on common operating systems.
Will these timestamp strings sort in date order?
Yes, if every value uses the same format and time-zone convention. The format is ordered from year down to seconds.
How can I include milliseconds?
Append fff:
string stamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
Should I store this formatted string in a database?
Usually no. Store a native date/time column or a DateTimeOffset value, then format it only when displaying or exporting it.
Why is my timestamp off by a few hours?
You may be formatting local time while another system expects UTC, or the reverse. Decide on a time-zone convention and convert explicitly with ToUniversalTime() when appropriate.
Mini Project
Description
Create a small console application that produces a timestamped export filename. This mirrors a common task in reports, backups, and batch jobs: generating filenames that sort chronologically and do not contain invalid punctuation.
Goal
Generate a UTC CSV filename in the form orders-yyyyMMddHHmmss.csv.
Requirements
Create the timestamp from the current UTC time.
Format the timestamp as yyyyMMddHHmmss.
Prefix it with orders-.
Add the .csv extension.
Print the final filename to the console.
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.