Powrót do strony głównej

Parser dat JavaScript: ukryte błędy i poprawki

Artykuł analizuje nieoczekiwane zachowanie konstruktora Date w JavaScript, parsującego daty z dowolnego tekstu. Opisano algorytm V8, problemy z timezone i rekomendacje dotyczące bezpiecznego parsowania dla production.

Dlaczego JS zamienia tekst w daty: analiza parsera V8
Advertisement 728x90

Niebezpieczny parser dat w JavaScript: jak uniknąć błędów przy pracy ze stringami

Konstruktor new Date(string) w JavaScript próbuje wyodrębnić datę z dowolnego ciągu znaków, co prowadzi do nieoczekiwanych wyników. To nie błąd — to cecha implementacji silników V8 i SpiderMonkey, gdzie parser agresywnie interpretuje tekst.

Przykłady pokazują problem:

new Date("2020-01-23")
// Wed Jan 22 2020 19:00:00 GMT-0500 (interpretacja UTC)

new Date("Today is 2020-01-23")
// Thu Jan 23 2020 00:00:00 GMT-0500 (czas lokalny)

new Date("Route 66")
// Sat Jan 01 1966 00:00:00 GMT-0500

new Date("Beverly Hills, 90210")
// Mon Jan 01 90210 00:00:00 GMT-0500

Takie przekształcenia tworzą poprawne obiekty Date, ale z nieprawidłowymi wartościami, co utrudnia debugowanie. Parser Catch 22 zwraca Invalid Date — rzadki przypadek, gdy logika działa poprawnie.

Google AdInline article slot

Mechanizm parsowania w V8

Specyfikacja ECMAScript wymaga parsowania tylko podzbioru ISO 8601. Reszta zależy od implementacji.

Algorytm V8:

  • Sprawdzenie formatu ISO 8601: ciąg musi zaczynać się od czterocyfrowego roku lub znaku.
  • Przejście do legacy-parsera: ignorowanie słów przed pierwszą liczbą.
  • Przetwarzanie liczb w DayComposer:

- 1–12: miesiąc.

Google AdInline article slot

- 13–31: niejednoznaczne, często odrzucane.

- 32+: rok (50–99 +1900).

- Domyślnie: 1 stycznia.

Google AdInline article slot

To wyjaśnia, dlaczego "Route 66" to rok 1966, a "90210" to rok 90210.

Problemy z strefami czasowymi

Ciągi ISO takie jak "2020-01-23" są parsowane jako UTC, legacy — jako czas lokalny. Różnica wynika z prefiksów:

  • Czysta ISO: UTC.
  • Z tekstem: legacy, czas lokalny.

Spacje na początku lub końcu ciągu zmieniają parsera, przesuwając wynik o dobę w zależności od strefy czasowej.

Safari (JavaScriptCore) jest bardziej rygorystyczny: odrzuca przykłady legacy oraz ciągi z końcowymi spacjami.

Praktyczne błędy i rozwiązania

W projektach rzeczywistych fallback na new Date() dla danych użytkownika zamienia "Route 66" na datę, psując tabele. Rozwiązanie: polegaj wyłącznie na własnych parserach z walidacją regex.

Zalecenia dla programistów średniozaawansowanych i seniorów:

  • Waliduj format za pomocą regex przed użyciem new Date().
  • Używaj date-fns parseISO() do ścisłego parsowania ISO.
  • Dla pełnej kontroli — biblioteki typu Luxon lub Day.js z niestandardowymi parserami.
  • Unikaj new Date(string) z niezweryfikowanymi danymi.
  • Testuj cross-browserowo: V8, SpiderMonkey, JSC.

Porównanie z Pythonem

Python unika dwuznaczności:

  • datetime.fromisoformat(): tylko ISO 8601.
  • strptime(): ścisły format, bez nadmiarowych znaków.

JavaScript legacy-parser domyśla się cicho, Python rzuca ValueError.

Co ważne

  • Parser Date tworzy poprawne, ale nieprawidłowe obiekty z losowego tekstu.
  • Różnica między parserami (ISO vs legacy) zależy od prefiksów i spacji.
  • W środowisku produkcyjnym: zawsze waliduj dane wejściowe przed parsowaniem.
  • Przejdź na Temporal API dla kodu przyszłości.
  • Testy cross-browserowe są obowiązkowe z powodu różnic w silnikach.

— Editorial Team

Advertisement 728x90

Czytaj dalej