Menu

Formatowanie DateTime w C#: formaty standardowe i niestandardowe, kultura, ISO 8601

Jak sformatować DateTime jako napis w C#: standardowe ciągi formatu (d, D, o, s, u, t), wzorce niestandardowe takie jak yyyy-MM-dd HH:mm:ss, pełna tabela specyfikatorów, wpływ kultury na wynik, zapis ISO 8601 z "o" oraz pomyłki mm zamiast MM i hh zamiast HH.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

DateTime.ToString(format) zamienia datę na tekst. Format to albo standardowy ciąg formatu (jedna litera, taka jak d lub o, której dokładny wzorzec pochodzi z kultury), albo niestandardowy wzorzec zbudowany ze specyfikatorów takich jak yyyy, MM i HH. Te same ciągi działają w interpolacji, $"{date:yyyy-MM-dd}", i w string.Format.

Wynik:

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

Przykłady na tej stronie przekazują CultureInfo.InvariantCulture, żeby wynik był taki sam na każdej maszynie; bez tego ToString używa bieżącej kultury, która może zmienić nazwy miesięcy, separatory, a nawet kalendarz.

Niestandardowe specyfikatory formatu

Format niestandardowy to wzorzec, w którym określone litery oznaczają części daty. Rozróżniają wielkość liter: M to miesiąc, a m to minuta, H to godzina w formacie 24-godzinnym, a h w 12-godzinnym.

SpecyfikatorZnaczeniePrzykład dla 2026-10-09 18:30:07.045
yyyyRok, 4 cyfry2026
yyRok, 2 cyfry26
MMMMPełna nazwa miesiącaOctober
MMMSkrócona nazwa miesiącaOct
MMMiesiąc, 2 cyfry10
MMiesiąc, 1 lub 2 cyfry10
ddddPełna nazwa dniaFriday
dddSkrócona nazwa dniaFri
ddDzień miesiąca, 2 cyfry09
dDzień miesiąca, 1 lub 2 cyfry (we wzorcu)9
HHGodzina, od 00 do 2318
HGodzina, od 0 do 2318
hhGodzina, od 01 do 1206
hGodzina, od 1 do 126
mmMinuta, 2 cyfry30
ssSekunda, 2 cyfry07
fffMilisekundy045
fffffffTakty (siedem cyfr ułamkowych)0450000
ttOznaczenie AM/PMPM
zzzPrzesunięcie względem UTC (DateTimeOffset lub czas lokalny)+02:00
KInformacja o strefie: Z, przesunięcie albo nicZ (dla wartości UTC)
/Separator daty z kultury/ lub . lub -
:Separator czasu z kultury:
'text' lub \cDosłowny tekst lub znak'at'

Każdy inny znak jest kopiowany bez zmian. Dotyczy to także liter, które nie są specyfikatorami, dlatego "YYYY-DD" po cichu wypisuje YYYY-DD: w .NET nie ma specyfikatorów z wielkim Y ani D.

Pojedyncza litera sama w sobie jest czytana jako format standardowy, a nie niestandardowy: ToString("d") to wzorzec krótkiej daty, a nie numer dnia. Żeby dostać sam dzień, napisz ToString("%d") albo użyj właściwości Day.

Wynik:

10/09/2026
9
20261009_183007
Week of Oct 9
18h30
2026-10-09T18:30:07
YYYY-DD

Standardowe ciągi formatu

Formaty standardowe to pojedyncze litery, których faktyczny wzorzec określa kultura. Są właściwym wyborem dla tekstu pokazywanego użytkownikom, bo każda kultura dostaje za darmo własne konwencje.

Wynik:

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
KodNazwaZależy od kultury?
d / DKrótka / długa dataTak
t / TKrótki / długi czasTak
f / FDługa data z krótkim / długim czasemTak
g / GKrótka data z krótkim / długim czasemTak
MMiesiąc i dzieńTak
YRok i miesiącTak
oISO 8601 round-trip, 7 cyfr ułamkowych, strefaNie
sSortowalny ISO 8601, bez ułamków, bez strefyNie
uUniwersalny sortowalny, kończy się na ZNie
rRFC 1123, dla nagłówków HTTPNie

o, s, u i r dają ten sam tekst w każdej kulturze, dlatego są bezpieczne w logach, nazwach plików i wymianie danych. Pamiętaj, że dla DateTime formaty u i r nie konwertują wartości na UTC; wypisują ją bez zmian i oznaczają jako UTC, więc jeśli wartość jest lokalna, najpierw wywołaj ToUniversalTime() (albo użyj DateTime.UtcNow). (Dla DateTimeOffset konwertują.)

Kultura zmienia wynik

Formaty standardowe, nazwy miesięcy i dni oraz separatory / i : pochodzą z kultury. Przekaż ją jako drugi argument ToString:

Wynik:

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

Dane kultur nie są zamrożone. .NET na Linuksie i macOS odczytuje je z biblioteki ICU zainstalowanej w systemie, a od .NET 5 robi to również .NET na Windows 10 i nowszych (.NET Framework używa własnych danych NLS z Windows), więc wzorzec może się nieznacznie zmieniać między wersjami i platformami: na przykład nowsze wydania ICU wstawiają przed "PM" w amerykańskim formacie krótkiego czasu wąską spację nierozdzielającą zamiast zwykłej spacji, a niektóre podają hiszpańskie krótkie daty bez zera na początku. To kolejny powód, żeby nigdy nie parsować tekstu sformatowanego do wyświetlania.

Wynikają z tego dwie zasady. Tekst czytany przez człowieka formatuj w jego kulturze (na serwerze w kulturze z żądania, a nie serwera) i wybieraj formaty standardowe, żeby czytelnik z Niemiec zobaczył 09.10.2026, a z USA 10/9/2026. Tekst czytany przez program formatuj z CultureInfo.InvariantCulture i jednoznacznym wzorcem, takim jak yyyy-MM-dd lub o. Data zapisana w bieżącej kulturze i sparsowana na innej maszynie to klasyczne źródło zamienionych dni i miesięcy.

ISO 8601 i round-trip z "o"

Format round-trip "o" zapisuje każdy takt oraz informację o strefie, więc sparsowanie tekstu zwraca dokładnie ten sam DateTime, łącznie z jego Kind:

Wynik:

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

Przyrostek Z oznacza UTC; DateTime z Kind równym Unspecified nie dostaje przyrostka; czas lokalny lub DateTimeOffset dostaje swoje przesunięcie (+02:00). Parsuj z DateTimeStyles.RoundtripKind, żeby Kind się zachował. Serializatory JSON, bazy danych i Date w JavaScripcie odczytują ten format.

Formatowanie TimeSpan

TimeSpan ma własny, mniejszy zestaw specyfikatorów niestandardowych: d (dni), hh, mm, ss i fff. W przeciwieństwie do DateTime każdy dosłowny znak, w tym : i ., trzeba poprzedzić ukośnikiem wstecznym albo ująć w cudzysłów:

Wynik:

1.03:25:09.1200000
1.03:25:09.1200000
03:25:09
1.03:25
25:09.120
27:25

hh w formacie TimeSpan to składnik godzin (od 0 do 23), więc czas trwania 27 godzin wypisuje się jako 03. Dla sum powyżej doby licz z TotalHours, jak w ostatniej linii. elapsed.ToString("hh:mm") bez ukośnika wstecznego rzuca FormatException.

Częste błędy

  • mm jako miesiąc. "yyyy-mm-dd" wypisuje minuty w środku: 2026-30-09. Miesiąc to MM.
  • hh bez tt. "hh:mm" to zegar 12-godzinny bez AM i PM, więc 06:30 jest niejednoznaczne. Dla czasu 24-godzinnego użyj HH.
  • YYYY i DD. W .NET to nie są specyfikatory; wypisują się dosłownie. Użyj yyyy i dd.
  • / we wzorcu dla danych. To separator daty z kultury. Ujmij go w cudzysłów albo użyj kultury niezmiennej.
  • Domyślne ToString() w logach lub plikach. Format zależy od maszyny. Przekaż format i kulturę.
  • Czas lokalny oznaczony jako UTC. "u", "r" i ręcznie wpisane 'Z' nie konwertują; najpierw skonwertuj.
  • Parsowanie innym wzorcem niż ten użyty przy zapisie. Trzymaj ciągi formatu dla danych w jednej stałej i używaj jej zarówno w ToString, jak i w ParseExact.

Najczęściej zadawane pytania

Jak sformatować DateTime jako yyyy-MM-dd w C#?

date.ToString("yyyy-MM-dd") daje 2026-10-09. W napisie interpolowanym napisz $"{date:yyyy-MM-dd}". Dodaj " HH:mm:ss", żeby dostać godzinę w formacie 24-godzinnym. Gdy tekst trafia do pliku lub innego programu, przekaż CultureInfo.InvariantCulture jako drugi argument, żeby kalendarz, nazwy miesięcy i separatory nigdy nie zależały od maszyny.

Czym różni się mm od MM w formatach dat C#?

MM to miesiąc (od 01 do 12), a mm to minuta (od 00 do 59). Format rozróżnia wielkość liter, więc yyyy-mm-dd wypisuje minuty tam, gdzie powinien być miesiąc, a taki błąd łatwo przeoczyć, patrząc na jedną wartość. Podobnie HH to godzina w formacie 24-godzinnym, a hh w 12-godzinnym.

Jak sformatować DateTime w ISO 8601 w C#?

Użyj formatu round-trip "o": DateTime.UtcNow.ToString("o") daje 2026-10-09T18:30:07.0450000Z, z siedmioma cyframi ułamkowymi i Z dla UTC albo przesunięciem dla czasu lokalnego. "s" daje krótszą, sortowalną postać bez ułamków i strefy, a "yyyy-MM-ddTHH:mm:ssZ" to popularny wariant niestandardowy.

Jak pokazać AM i PM w formacie daty C#?

Użyj hh lub h dla zegara 12-godzinnego i tt dla oznaczenia AM/PM: date.ToString("h:mm tt", CultureInfo.GetCultureInfo("en-US")) daje 6:30 PM. Oznaczenie pochodzi z kultury, a niektóre kultury go nie mają, więc gdy potrzebujesz AM i PM, przekaż kulturę jawnie.

Dlaczego mój format daty pokazuje kropki zamiast ukośników?

W ciągu formatu / nie jest dosłownym ukośnikiem, tylko separatorem daty z kultury, a : to separator czasu z kultury. Na niemieckiej maszynie dd/MM/yyyy wypisuje 09.10.2026. Ujmij znak w cudzysłów, żeby go wymusić, dd'/'MM'/'yyyy, albo formatuj z CultureInfo.InvariantCulture.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ