Jaki format znaczników czasu w JSON
Podsumowanie: Liczby epoki i łańcuchy ISO mają różne kompromisy, ale to ich mieszanie naprawdę psuje sprawę. Używaj ISO 8601 z przesunięciem, przechowuj UTC, renderuj w strefie czasowej użytkownika.

Najważniejsze: używaj ISO 8601 z jawnym przesunięciem na łączu, przechowuj UTC z końcowym Z i konwertuj tylko w czasie wyświetlania; jeśli zamiast tego wybierzesz liczby epoki, ustal globalnie sekundy vs milisekundy i umieść jednostkę w nazwie pola.
Dlaczego 2026-10-30 14:30:00 nie wystarczy
Ten łańcuch nie niesie strefy. 14:30 w Szanghaju i 14:30 w Londynie różnią się o osiem godzin, i nie ma jak odróżnić, o którą chodzi. new Date('2026-10-30 14:30:00') parsuje w strefie lokalnej środowiska wykonania, więc serwer i przeglądarka wyprowadzają dwa różne momenty z jednego ładunku — bug, który nigdy się nie reprodukuje.
Samo 2026-10-30 w ogóle nie jest momentem. W porządku dla urodzin i okresów rozliczeniowych, złe dla czasu utworzenia.
Dwa wykonalne formaty
Łańcuchy ISO 8601
{
"createdAt": "2026-10-30T14:30:00+08:00",
"updatedAt": "2026-10-30T06:30:00Z"
}
Czytelne, sortowalne przy spójnym formacie, precyzja milisekundowa w razie potrzeby i samoopisujące się.
Liczby epoki
{ "createdAt": 1793519400 }
Zwięzłe i jednoznaczne, ale nieczytelne, a sekundy vs milisekundy to trwałe zagrożenie. Jeśli wybierasz epoki, ustandaryzuj jednostkę i umieść ją w nazwie pola: createdAtMs jest znacznie bezpieczniejsze niż createdAt.
Konwencje warte ustalenia wcześnie
| Element | Konwencja |
|---|---|
| Format łącza | ISO 8601 z Z lub +08:00 |
| Strefa przechowywania | UTC, aby czas letni nigdy nie wchodził w grę |
| Precyzja | Milisekundy wystarczą |
| Nazewnictwo pól | createdAt, updatedAt, expiresAt |
| Czyste daty | Osobne pole date, np. birthday: "1990-01-01" |
| Czas trwania | Liczba całkowita plus jednostka, np. timeoutMs: 3000 |
Renderowanie
new Intl.DateTimeFormat('en-GB', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Europe/London',
}).format(new Date('2026-10-30T06:30:00Z'));
Określaj timeZone jawnie, gdy wyświetlanie nie ma podążać za urządzeniem. Poleganie na domyślności przeglądarki jest poprawne dla czasów widocznych dla użytkownika i błędne dla raportów.
Trzy powracające bugi
Same daty parsują się jako północ UTC. Zgodnie ze specyfikacją ECMAScript łańcuchy zawierające tylko datę są UTC, a data-czas lokalne. Ta niespójność jest niezawodnym źródłem błędów przesunięcia o jeden dzień.
Strefa bazy nie zgadza się z serializatorem. MySQL datetime nie ma strefy; zapisz lokalnie, czytaj jako UTC, a wszystko przesunie się o offset.
Czas letni. Przechowywanie przyszłych czasów lokalnych tworzy momenty, które nie istnieją albo wystąpią dwa razy. UTC nie ma takich luk.
FAQ
Jak wybrać między ISO 8601 a liczbami epoki?
Użyj ISO 8601, gdy ludzie czytają ładunek, gdy chcesz porządku sortowania leksykalnego albo gdy wartość musi nieść własną strefę; koszt to około kilkunastu dodatkowych bajtów i biblioteka parsująca. Użyj liczb epoki, gdy zwięzłość i trywialna obsługa między językami liczą się bardziej, ale ustal globalnie sekundy vs milisekundy i powiedz, którą jednostkę trzyma pole.
Czy sama data i znacznik czasu powinny dzielić to samo pole?
Nie. Samo 2026-10-30 to dzień kalendarzowy bez czasu i strefy, podczas gdy pole znacznika czasu ma nieść dokładny moment. Trzymaj urodziny i okresy rozliczeniowe w osobnym polu date, a do czasów utworzenia lub aktualizacji używaj pola ISO 8601 At.