Menu

Формат DateTime в C#: стандартные и пользовательские форматы, культура, ISO 8601

Как отформатировать DateTime в строку в C#: стандартные строки формата (d, D, o, s, u, t), пользовательские шаблоны вроде yyyy-MM-dd HH:mm:ss, полная таблица спецификаторов, влияние культуры на вывод, ISO 8601 с "o" и ошибки с mm и MM, hh и HH.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

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 до 2318
HЧас, от 0 до 2318
hhЧас, от 01 до 1206
hЧас, от 1 до 126
mmМинуты, 2 цифры30
ssСекунды, 2 цифры07
fffМиллисекунды045
fffffffТики (семь дробных цифр)0450000
ttОбозначение AM/PMPM
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Год и месяцДа
oISO 8601 для обратного разбора, 7 дробных цифр, поясНет
sСортируемый ISO 8601, без долей секунды и поясаНет
uУниверсальный сортируемый, заканчивается на ZНет
rRFC 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.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ