DateTime.ToString(format) превращает дату в текст. Формат это либо стандартная строка формата (одна буква, например d или o, точный шаблон которой берётся из культуры), либо пользовательский шаблон из спецификаторов вроде yyyy, MM и HH. Те же строки работают в интерполяции, $"{date:yyyy-MM-dd}", и в string.Format.
Вывод:
2026-10-09
2026-10-09 18:30:07
09/10/2026
Oct 9, 2026
Friday, October 9
6:30 PM
18:30:07.045
Shipped 2026-10-09 at 18:30
Примеры на этой странице передают CultureInfo.InvariantCulture, чтобы вывод был одинаковым на любой машине; без неё ToString использует текущую культуру, которая может поменять названия месяцев, разделители и даже календарь.
Пользовательские спецификаторы формата
Пользовательский формат это шаблон, в котором определённые буквы обозначают части даты. Они чувствительны к регистру: M это месяц, а m минуты, H это часы в 24-часовом формате, а h в 12-часовом.
| Спецификатор | Значение | Пример для 2026-10-09 18:30:07.045 |
|---|---|---|
yyyy | Год, 4 цифры | 2026 |
yy | Год, 2 цифры | 26 |
MMMM | Полное название месяца | October |
MMM | Сокращённое название месяца | Oct |
MM | Месяц, 2 цифры | 10 |
M | Месяц, 1 или 2 цифры | 10 |
dddd | Полное название дня | Friday |
ddd | Сокращённое название дня | Fri |
dd | День месяца, 2 цифры | 09 |
d | День месяца, 1 или 2 цифры (внутри шаблона) | 9 |
HH | Час, от 00 до 23 | 18 |
H | Час, от 0 до 23 | 18 |
hh | Час, от 01 до 12 | 06 |
h | Час, от 1 до 12 | 6 |
mm | Минуты, 2 цифры | 30 |
ss | Секунды, 2 цифры | 07 |
fff | Миллисекунды | 045 |
fffffff | Тики (семь дробных цифр) | 0450000 |
tt | Обозначение AM/PM | PM |
zzz | Смещение от UTC (DateTimeOffset или локальное время) | +02:00 |
K | Информация о поясе: Z, смещение или ничего | Z (для значения в UTC) |
/ | Разделитель даты культуры | / или . или - |
: | Разделитель времени культуры | : |
'text' или \c | Буквальный текст или символ | 'at' |
Любой другой символ копируется как есть. Это касается и букв, которые не являются спецификаторами, поэтому "YYYY-DD" молча печатает YYYY-DD: в .NET нет спецификаторов Y и D в верхнем регистре.
Одна буква сама по себе читается как стандартный формат, а не пользовательский: ToString("d") это шаблон короткой даты, а не номер дня. Чтобы получить только день, пишите ToString("%d") или используйте свойство Day.
Вывод:
10/09/2026
9
20261009_183007
Week of Oct 9
18h30
2026-10-09T18:30:07
YYYY-DD
Стандартные строки формата
Стандартные форматы это одиночные буквы, фактический шаблон которых определяет культура. Это правильный выбор для текста, который видят пользователи, потому что каждая культура бесплатно получает свои соглашения.
Вывод:
d 10/09/2026
D Friday, 09 October 2026
f Friday, 09 October 2026 18:30
g 10/09/2026 18:30
G 10/09/2026 18:30:07
M October 09
Y 2026 October
t 18:30
T 18:30:07
o 2026-10-09T18:30:07.0000000Z
s 2026-10-09T18:30:07
u 2026-10-09 18:30:07Z
r Fri, 09 Oct 2026 18:30:07 GMT
en-US d: 10/9/2026, D: Friday, October 9, 2026
| Код | Название | Зависит от культуры? |
|---|---|---|
d / D | Короткая / длинная дата | Да |
t / T | Короткое / длинное время | Да |
f / F | Длинная дата с коротким / длинным временем | Да |
g / G | Короткая дата с коротким / длинным временем | Да |
M | Месяц и день | Да |
Y | Год и месяц | Да |
o | ISO 8601 для обратного разбора, 7 дробных цифр, пояс | Нет |
s | Сортируемый ISO 8601, без долей секунды и пояса | Нет |
u | Универсальный сортируемый, заканчивается на Z | Нет |
r | RFC 1123, для HTTP-заголовков | Нет |
o, s, u и r дают одинаковый текст в любой культуре, поэтому их безопасно использовать для логов, имён файлов и обмена данными. Учтите, что для DateTime форматы u и r не переводят значение в UTC; они печатают его как есть и помечают как UTC, поэтому если значение локальное, сначала вызовите ToUniversalTime() (или используйте DateTime.UtcNow). (Для DateTimeOffset преобразование выполняется.)
Культура меняет вывод
Стандартные форматы, названия месяцев и дней, а также разделители / и : берутся из культуры. Передайте её вторым аргументом в ToString:
Вывод:
en-US 10/9/2026
en-GB 09/10/2026
de-DE 09.10.2026
fr-FR 09/10/2026
ja-JP 2026/10/09
Freitag, 9. Oktober 2026
vendredi 9 octobre 2026
09.10.2026
09/10/2026
Данные культур не заморожены. .NET в Linux и macOS читает их из библиотеки ICU, установленной в системе, а начиная с .NET 5 так же делает .NET в Windows 10 и новее (.NET Framework использует собственные данные NLS Windows), поэтому шаблон может немного меняться между версиями и платформами: например, свежие выпуски ICU ставят перед «PM» в американском формате короткого времени узкий неразрывный пробел вместо обычного, а некоторые дают испанские короткие даты без ведущего нуля. Это ещё одна причина никогда не разбирать текст, отформатированный для отображения.
Отсюда два правила. Для текста, который читает человек, форматируйте с его культурой (на сервере с культурой из запроса, а не сервера) и предпочитайте стандартные форматы, чтобы немецкий читатель видел 09.10.2026, а американский 10/9/2026. Для текста, который читает программа, используйте CultureInfo.InvariantCulture и однозначный шаблон вроде yyyy-MM-dd или o. Дата, записанная с текущей культурой и разобранная на другой машине, это классический источник перепутанных дней и месяцев.
ISO 8601 и обратный разбор с «o»
Формат обратного преобразования "o" записывает каждый тик плюс информацию о поясе, поэтому разбор текста возвращает в точности тот же DateTime, включая его Kind:
Вывод:
2026-10-09T18:30:07.0450000Z
2026-10-09T18:30:07.0450000
2026-10-09T20:30:07.0000000+02:00
True
Utc
2026-10-09T18:30:07Z
2026-10-09 20:30 +02:00
Суффикс Z обозначает UTC; DateTime с Kind, равным Unspecified, суффикса не получает; локальное время или DateTimeOffset получает своё смещение (+02:00). Разбирайте с DateTimeStyles.RoundtripKind, чтобы Kind сохранился. Этот формат читают JSON-сериализаторы, базы данных и Date в JavaScript.
Форматирование TimeSpan
У TimeSpan свой, меньший набор пользовательских спецификаторов: d (дни), hh, mm, ss и fff. В отличие от DateTime, каждый буквальный символ, включая : и ., нужно экранировать обратным слешем или заключать в кавычки:
Вывод:
1.03:25:09.1200000
1.03:25:09.1200000
03:25:09
1.03:25
25:09.120
27:25
hh в формате TimeSpan это компонент часов (от 0 до 23), поэтому длительность в 27 часов печатается как 03. Для итогов больше суток вычисляйте из TotalHours, как в последней строке. elapsed.ToString("hh:mm") без обратного слеша выбрасывает FormatException.
Частые ошибки
mmвместо месяца."yyyy-mm-dd"печатает минуты посередине:2026-30-09. Месяц этоMM.hhбезtt."hh:mm"это 12-часовой формат без AM и PM, поэтому 06:30 неоднозначно. Для 24-часового времени используйтеHH.YYYYиDD. В .NET это не спецификаторы; они печатаются буквально. Используйтеyyyyиdd./в шаблоне для данных. Это разделитель даты культуры. Заключите его в кавычки или используйте инвариантную культуру.ToString()по умолчанию в логах или файлах. Формат зависит от машины. Передавайте формат и культуру.- Локальное время с пометкой UTC.
"u","r"и написанная вручную'Z'не преобразуют значение; сначала преобразуйте. - Разбор по другому шаблону, чем при записи. Храните строки формата для данных в одной константе и используйте её и с
ToString, и сParseExact.
Часто задаваемые вопросы
Как отформатировать DateTime как yyyy-MM-dd в C#?
date.ToString("yyyy-MM-dd") даёт 2026-10-09. В интерполированной строке пишите $"{date:yyyy-MM-dd}". Добавьте " HH:mm:ss" для времени в 24-часовом формате. Передавайте вторым аргументом CultureInfo.InvariantCulture, когда текст предназначен для файла или другой программы, чтобы календарь, названия месяцев и разделители не зависели от машины.
Чем mm отличается от MM в форматах дат C#?
MM это месяц (от 01 до 12), а mm это минуты (от 00 до 59). Формат чувствителен к регистру, поэтому yyyy-mm-dd печатает минуты на месте месяца, и эту ошибку легко пропустить, глядя на одно значение. Аналогично HH это часы в 24-часовом формате, а hh в 12-часовом.
Как отформатировать DateTime в ISO 8601 в C#?
Используйте формат обратного преобразования "o": DateTime.UtcNow.ToString("o") даёт 2026-10-09T18:30:07.0450000Z с семью дробными цифрами и Z для UTC или смещением для локального времени. "s" даёт более короткую сортируемую форму без долей секунды и пояса, а "yyyy-MM-ddTHH:mm:ssZ" это распространённый пользовательский вариант.
Как показать AM и PM в формате даты C#?
Используйте hh или h для 12-часового формата и tt для обозначения AM/PM: date.ToString("h:mm tt", CultureInfo.GetCultureInfo("en-US")) даёт 6:30 PM. Обозначение берётся из культуры, а в некоторых культурах его нет, поэтому когда нужны AM и PM, передавайте культуру явно.
Почему в формате даты точки вместо слешей?
В строке формата / это не буквальный слеш, а разделитель даты культуры, а : это разделитель времени культуры. На немецкой машине dd/MM/yyyy печатает 09.10.2026. Заключите символ в кавычки, чтобы вывести его буквально, dd'/'MM'/'yyyy, или форматируйте с CultureInfo.InvariantCulture.