Menu

Data w JavaScript: new Date, formatowanie i porównywanie

Jak naprawdę działa obiekt Date w JavaScript: tworzenie dat, formatowanie, dodawanie dni, strefy czasowe i pułapki, na których ludzie się potykają.

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

Obiekt Date to moment w czasie

Date w JavaScript reprezentuje jedną konkretną chwilę: wewnętrznie to po prostu liczba milisekund od 1 stycznia 1970 roku UTC (tak zwana „epoka Uniksa”). Cała reszta, czyli lata, miesiące, dni, strefy czasowe i formatowanie, to widok nałożony na tę liczbę.

now.getTime() to surowa liczba milisekund. Wszystko, co robi Date (porównywanie, dodawanie dni, formatowanie), sprowadza się do operacji na tej liczbie i ponownej jej interpretacji.

Zapamiętaj ten model. Date to nie „14 marca w Paryżu”. To uniwersalna chwila, którą można pokazać jako 14 marca w Paryżu albo 13 marca w Los Angeles, zależnie od strefy czasowej, przez którą na nią patrzysz.

Tworzenie dat

Są cztery główne sposoby na utworzenie obiektu Date:

Zwróć uwagę na dwie rzeczy:

  • Konstruktor z częściami używa miesięcy numerowanych od zera. 2 oznacza marzec. Styczeń to 0. To stałe źródło błędów o jeden, ale przynajmniej API jest konsekwentne: wszędzie miesiące liczy się od 0.
  • new Date("2026-03-14") (bez godziny) jest parsowane jako północ UTC. new Date("2026-03-14T09:30") (bez Z) jest parsowane jako czas lokalny. Ta asymetria to klasyczna pułapka.

Jeśli chcesz dostać „teraz” jako liczbę, wybierz Date.now(): nie tworzy obiektu.

Date.now() to właściwe narzędzie do mierzenia upływu czasu, limitów czasu i wszystkiego, co nie wymaga obliczeń kalendarzowych.

Odczytywanie części daty

Mając obiekt Date, wyciągasz z niego składniki za pomocą getterów. Każdy występuje w dwóch wersjach: dla czasu lokalnego i dla UTC.

Wersje lokalne zależą od komputera, na którym działa kod. Jeśli zapisujesz albo porównujesz daty między użytkownikami i serwerami, jawnie wybierz UTC, bo inaczej będziesz ścigać błędy widma. Praktyczna zasada: gettery UTC do wszystkiego, co trafia do bazy danych albo logu; gettery lokalne do tego, co za chwilę pokażesz człowiekowi.

Nie używaj getYear(). To przestarzała metoda, która zwraca year - 1900 i istnieje tylko dla zgodności. Zawsze sięgaj po getFullYear().

Formatowanie dla ludzi

Unikaj date.toString() wszędzie tam, gdzie wynik ma znaczenie: jego format zależy od ustawień regionalnych i silnika. Warto znać dwa formatery.

Do standardowego tekstu czytelnego dla maszyn użyj toISOString():

Tego formatu używasz przy logowaniu, zapisie do JSON i wysyłaniu przez sieć. Zawsze jest w UTC i zawsze jednoznaczny.

Do tekstu dla ludzi użyj Intl.DateTimeFormat albo metod toLocale*, które z niego korzystają:

Intl.DateTimeFormat obsługuje ustawienia regionalne, strefy czasowe i każdą kombinację pól, jakiej możesz potrzebować. Sięgnij po niego, zanim zaczniesz ręcznie składać ${year}-${month}-${day}: właśnie w takim sklejaniu tekstu żyją błędy z miesiącem przesuniętym o jeden.

Porównywanie dat

Dwa obiekty Date oznaczające tę samą chwilę nie są równe przez ===, bo === sprawdza tożsamość obiektów, a nie wartość. Porównuj zamiast tego ich znaczniki czasu:

Do ustalania kolejności operatory porównania działają bezpośrednio, bo zamieniają daty na liczby:

Odejmowanie daje różnicę w milisekundach. Podziel przez 1000 * 60 * 60 * 24, żeby dostać dni. Za pierwszym razem rozpisz tę stałą; z czasem 86_400_000 rozpoznasz na pierwszy rzut oka.

Arytmetyka na datach

Nie ma metody addDays. Idiomatyczny sposób to setDate, setMonth i podobne: przyjmują wartości spoza zakresu i poprawnie je przenoszą:

Dwie rzeczy warte podkreślenia:

  • new Date(date) kopiuje datę. setDate modyfikuje obiekt, więc zawsze najpierw zrób kopię, bo inaczej zmienisz wartość należącą do kodu wywołującego.
  • setDate(35) w miesiącu z 31 dniami automatycznie przechodzi na następny miesiąc. Tak samo setMonth(14) przesuwa rok. Dzięki temu arytmetyka jest dużo mniej bolesna, niż się wydaje.

Do wszystkiego bardziej złożonego (dni robocze, wydarzenia cykliczne, okresy uwzględniające miesiące) użyj biblioteki (date-fns, Luxon albo nadchodzącego API Temporal). Własne obliczenia kalendarzowe wykraczające poza „dodaj kilka dni” to grzęzawisko.

Strefy czasowe bez złudzeń

Strefy czasowe to największe pojedyncze źródło błędów z datami. Zasady, które warto sobie przyswoić:

  • Date przechowuje chwilę w UTC. Strefa czasowa jest stosowana dopiero przy odczycie części albo formatowaniu.
  • Strefa czasowa używana przez getHours(), getDate() itd. to lokalna strefa komputera, na którym działa kod. Serwery i przeglądarki często się w tym różnią.
  • new Date("2026-03-14") (sama data) jest parsowane jako UTC. new Date("2026-03-14T00:00") (z godziną, bez strefy) jako czas lokalny. new Date(2026, 2, 14) (z części) też jako czas lokalny.

Gdy musisz pokazać datę w konkretnej strefie czasowej, przekaż timeZone do Intl.DateTimeFormat:

Ta sama chwila, dwa widoki. Sam obiekt Date się nie zmienił.

Mały działający przykład

Wszystko razem: funkcja, która opisuje, jak dawno coś się wydarzyło:

Na wejściu znaczniki czasu, na wyjściu czytelny tekst. Tak wygląda 90% prawdziwego kodu z datami: odejmij dwie chwile, podziel przez jednostkę, zaokrąglij, sformatuj.

Co warto zapamiętać

  • Date to chwila w UTC. Strefy czasowe pojawiają się przy odczycie albo formatowaniu.
  • Używaj Date.now() do znaczników czasu, a new Date() do pracy z kalendarzem.
  • toISOString() do zapisu i logów, Intl.DateTimeFormat dla użytkowników.
  • Porównuj przez getTime() albo </>. Nigdy przez ===.
  • Miesiące liczy się od 0. Uważaj na pułapkę przy parsowaniu tekstu z samą datą.
  • Do poważnych obliczeń na datach użyj biblioteki.

Dalej: adresy URL i query stringi

Daty często trafiają do adresów URL: filtrowanie po zakresie dat, znacznik czasu jako parametr zapytania. Ręczne parsowanie i budowanie adresów URL jest tak samo podatne na błędy jak ręczne formatowanie dat, a biblioteka standardowa ma obiekt URL, który robi to porządnie. O tym jest następna strona.

Najczęściej zadawane pytania

Jak pobrać aktualną datę w JavaScript?

Wywołaj new Date() bez argumentów. Zwraca obiekt Date reprezentujący chwilę, w której uruchomiono konstruktor. Jeśli potrzebujesz tylko liczbowego znacznika czasu (milisekundy od 1970 roku), użyj Date.now(): jest szybsze i nie tworzy całego obiektu.

Jak porównać dwie daty w JavaScript?

Porównuj ich znaczniki czasu, a nie same obiekty Date. a.getTime() < b.getTime() działa, podobnie jak a < b, bo < zamienia daty na liczby. Ale a === b nie działa: === sprawdza tożsamość obiektów, więc dwa obiekty Date oznaczające tę samą chwilę nigdy nie są ściśle równe.

Jak sformatować datę w JavaScript?

Do wszystkiego, co widzi użytkownik, używaj Intl.DateTimeFormat albo date.toLocaleDateString(): poprawnie obsługują języki i strefy czasowe. Do danych dla maszyn date.toISOString() daje standardowy tekst, np. 2026-03-14T09:30:00.000Z. Unikaj date.toString() przy zapisywaniu danych, bo jego format zależy od ustawień regionalnych.

Dlaczego moja data w JavaScript przesuwa się o jeden dzień?

Zwykle to kwestia strefy czasowej. new Date('2026-03-14') jest parsowane jako północ UTC, ale date.getDate() zwraca dzień w lokalnej strefie czasowej, a to może być dzień wcześniej. Użyj getUTCDate(), żeby dostać dzień w UTC, albo twórz daty przez new Date(year, month, day), które od początku używa czasu lokalnego.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ