Nebezpečný parser dat v JavaScript: Jak se vyhnout chybám při práci se řetězci
Konstruktor new Date(string) v JavaScriptu se snaží extrahovat datum z jakéhokoli řetězce, což často vede k neočekávaným výsledkům. Toto není chyba, ale specifická funkce implementací V8 a SpiderMonkey, kde parser agresivně interpretuje text.
Příklady ukazují problém:
new Date("2020-01-23")
// Wed Jan 22 2020 19:00:00 GMT-0500 (interpretace UTC)
new Date("Dnes je 2020-01-23")
// Thu Jan 23 2020 00:00:00 GMT-0500 (místní čas)
new Date("Trasa 66")
// Sat Jan 01 1966 00:00:00 GMT-0500
new Date("Beverly Hills, 90210")
// Mon Jan 01 90210 00:00:00 GMT-0500
Takové převody vytvářejí platné objekty Date, ale s nesprávnými hodnotami, což komplikuje ladění. Parser Catch 22 vrací Invalid Date — vzácný případ, kdy logika funguje správně.
Mechanismus parsování ve V8
Specifikace ECMAScript požaduje parsování pouze podmnožiny ISO 8601. Ostatní části jsou na uvážení implementace.
Algoritmus V8:
- Kontrola na ISO 8601: řetězec musí začínat čtyřciferným rokem nebo znaménkem.
- Přechod do legacy-parsovače: ignorování slov před prvním číslem.
- Zpracování čísel v
DayComposer:
- 1–12: měsíc.
- 13–31: nejednoznačné, často odmítnuto.
- 32+: rok (50–99 +1900).
- Ve výchozím stavu: 1. leden.
To vysvětluje, proč "Route 66" je považováno za rok 1966 a "90210" za rok 90210.
Problémy s časovými pásmi
ISO řetězce jako "2020-01-23" se parsovaly jako UTC, legacy jako místní čas. Rozdíl vzniká kvůli předponám:
- Čistá ISO: UTC.
- S textem: legacy, místní čas.
Prázdné znaky na začátku nebo konci řetězce mění parser a posouvá výsledek o den podle časového pásma.
Safari (JavaScriptCore) je striktnější: odmítá legacy příklady a řetězce s koncovými mezerami.
Praktické chyby a řešení
V reálných projektech fallback na new Date() pro uživatelská data převede "Route 66" na datum, což poškozuje tabulky. Řešení: spoléhat pouze na vlastní parsovače s regex validací.
Doporučení pro střední a senior vývojáře:
- Validujte formát pomocí regex před voláním
new Date(). - Použijte
date-fns parseISO()pro přísné ISO. - Pro plnou kontrolu: knihovny jako Luxon nebo Day.js s vlastními parsovači.
- Vyhněte se
new Date(string)s neověřenými daty. - Testujte křížově prohlížečově: V8, SpiderMonkey, JSC.
Porovnání s Pythonem
Python vyhýbá neurčitosti:
datetime.fromisoformat(): pouze ISO 8601.strptime(): přísný formát bez nepotřebných znaků.
JavaScript legacy-parser hádá tichounce, Python vyhazuje ValueError.
Co je důležité
- Parser
Datevytváří platné, ale nesprávné objekty z náhodného textu. - Rozdíl mezi parsery (ISO vs legacy) závisí na předponách a mezerách.
- V produkci: vždy ověřujte vstup před parsováním.
- Přejděte na Temporal API pro budoucnost bezpečný kód.
- Křížové testování prohlížečů je povinné kvůli rozdílům v enginech.
— Editorial Team
Zatím žádné komentáře.