Primul caz:

Ieșire:

Vin 08 Iul 2005 00:00:00 GMT-0700 (PST)

toate browserele

Al doilea caz:

Ieșire:

Joi 07 iulie 2005 17:00:00 GMT-0700 (PST)

De ce este a doua analiză incorectă?

11 Răspunsuri 11

Până la apariția specificației ediției a 5-a, metoda Date.parse a fost complet dependentă de implementare (data nouă (șir) este echivalentă cu Date.parse (șir), cu excepția faptului că acesta din urmă returnează un număr mai degrabă decât o dată). În specificația ediției a 5-a, cerința a fost adăugată pentru a accepta un ISO-8601 simplificat (și ușor incorect) (a se vedea, de asemenea, Ce sunt șirurile de date și ora valide în JavaScript?). Dar, în afară de asta, nu a existat nicio cerință pentru ce Date.parse/new Date (șir) ar trebui să accepte, în afară de faptul că trebuiau să accepte orice ieșire Date # toString (fără să spună ce este asta).

Începând cu ECMAScript 2017 (ediția 8), implementările au fost necesare pentru a analiza rezultatul pentru Date # toString și Date # toUTCString, dar formatul acestor șiruri nu a fost specificat.

Începând cu ECMAScript 2019 (ediția 9), formatul pentru Date # toString și Date # toUTCString, a fost specificat ca (respectiv):

  1. ddd MMM DD AAAA HH: mm: ss ZZ [(numele fusului orar)]
    de exemplu. Mar 10 iul 2018 18:39:58 GMT + 0530 (IST)
  2. ddd, DD MMM AAAA HH: mm: ss Z
    de exemplu. Marți 10 iul 2018 13:09:58 GMT

furnizarea a încă 2 formate pe care Date.parse ar trebui să le analizeze în mod fiabil în noile implementări (menționând că suportul nu este omniprezent și implementările neconforme vor rămâne utilizate pentru o perioadă de timp).

Aș recomanda ca șirurile de date să fie analizate manual și constructorul de date să fie folosit cu argumente de an, lună și zi pentru a evita ambiguitatea:

În timpul experienței recente de scriere a unui interpret JS, m-am luptat mult cu funcționarea interioară a datelor ECMA/JS. Deci, cred că îmi voi arunca cei 2 cenți aici. Sperăm că partajarea acestor lucruri îi va ajuta pe ceilalți cu orice întrebări cu privire la diferențele dintre browsere în modul în care gestionează datele.

Toate implementările își stochează valorile datei intern ca numere pe 64 de biți care reprezintă numărul de milisecunde (ms) din 1970-01-01 UTC (GMT este același lucru cu UTC). Această dată este epoca ECMAScript care este utilizată și de alte limbaje, cum ar fi sistemele Java și POSIX, cum ar fi UNIX. Datele care apar după epocă sunt numere pozitive, iar datele anterioare sunt negative.

Următorul cod este interpretat ca aceeași dată în toate browserele curente, dar cu compensarea fusului orar local:

În fusul meu orar (EST, care este -05: 00), rezultatul este 18000000 pentru că atât sunt mulți ms în 5 ore (sunt doar 4 ore în lunile de vară). Valoarea va fi diferită în diferite fusuri orare. Acest comportament este specificat în ECMA-262, deci toate browserele o fac în același mod.

Deși există o oarecare variație în formatele șirurilor de intrare pe care browserele majore le vor analiza ca date, ele le interpretează în esență la fel în ceea ce privește fusurile orare și ora de vară, deși analiza depinde în mare măsură de implementare.

Cu toate acestea, formatul ISO 8601 este diferit. Este unul dintre cele două formate descrise în ECMAScript 2015 (ed. 6) în mod specific, care trebuie analizate în același mod de toate implementările (celălalt este formatul specificat pentru Date.prototype.toString).

Dar, chiar și pentru șirurile de format ISO 8601, unele implementări greșesc. Iată o ieșire de comparație a Chrome și Firefox când acest răspuns a fost scris inițial pentru 1/1/1970 (epoca) pe mașina mea folosind șiruri de format ISO 8601 care ar trebui să fie analizate exact la aceeași valoare în toate implementările:

  • În primul caz, specificatorul „Z” indică faptul că intrarea este în timpul UTC, deci nu este compensată de epocă și rezultatul este 0
  • În al doilea caz, specificatorul „-0500” indică faptul că intrarea este în GMT-05: 00 și ambele browsere interpretează intrarea ca fiind în fusul orar -05: 00. Asta înseamnă că valoarea UTC este compensată de epocă, ceea ce înseamnă adăugarea a 18000000ms la valoarea internă a datei.
  • Al treilea caz, în care nu există un specificator, ar trebui tratat ca local pentru sistemul gazdă. FF tratează corect intrarea ca oră locală, în timp ce Chrome o tratează ca UTC, producând astfel valori de timp diferite. Pentru mine acest lucru creează o diferență de 5 ore în valoarea stocată, ceea ce este problematic. Alte sisteme cu compensări diferite vor obține rezultate diferite.

Această diferență a fost remediată din 2020, dar există alte ciudățenii între browsere atunci când se analizează șirurile de format ISO 8601.

Dar se înrăutățește. O ciudățenie a ECMA-262 este că formatul ISO 8601 numai pentru dată (AAAA-LL-ZZ) este necesar să fie analizat ca UTC, în timp ce ISO 8601 necesită ca acesta să fie analizat ca local. Iată ieșirea din FF cu formatele de date ISO lungi și scurte, fără specificator de fus orar.

Deci primul este analizat ca local deoarece este data și ora ISO 8601 fără fus orar, iar al doilea este analizat ca UTC deoarece este doar data ISO 8601.

Deci, pentru a răspunde direct la întrebarea inițială, „AAAA-LL-ZZ” este cerută de ECMA-262 să fie interpretată ca UTC, în timp ce cealaltă este interpretată ca locală. De aceea:

Acest lucru nu produce rezultate echivalente:

Acest lucru face:

Linia de jos este aceasta pentru analizarea șirurilor de date. SINGURUL șir ISO 8601 pe care îl puteți analiza în siguranță între browsere este forma lungă cu un offset (fie ± HH: mm sau „Z”). Dacă faceți acest lucru, puteți merge în siguranță înainte și înapoi între ora locală și ora UTC.

Acest lucru funcționează în toate browserele (după IE9):

Majoritatea browserelor actuale tratează celelalte formate de intrare în mod egal, inclusiv „1/1/1970” (M/Z/AAAA) și „1/1/1970 00:00:00 AM” (M/Z/AAAA hh): mm: ss ap) formate. Toate formatele următoare (cu excepția ultimului) sunt tratate ca intrare de oră locală în toate browserele. Ieșirea acestui cod este aceeași în toate browserele din fusul meu orar. Ultimul este tratat ca -05: 00 indiferent de fusul orar al gazdei, deoarece offset-ul este setat în marcajul de timp:

Cu toate acestea, deoarece analiza chiar și a formatelor specificate în ECMA-262 nu este consecventă, se recomandă să nu vă bazați niciodată pe parserul încorporat și să analizați întotdeauna manual șirurile, să spunem folosind o bibliotecă și să furnizați formatul parserului.

De exemplu. în moment.js ați putea scrie:

Pe partea de ieșire, toate browserele traduc fusurile orare în același mod, dar gestionează formatele șirului diferit. Iată funcțiile toString și ceea ce produc. Observați funcțiile toUTCString și toISOString care ies la 5:00 AM pe mașina mea. De asemenea, numele fusului orar poate fi o abreviere și poate fi diferit în diferite implementări.

Convertește de la UTC la ora locală înainte de tipărire

Tipărește ora UTC stocată direct

În mod normal, nu folosesc formatul ISO pentru introducerea șirului. Singura dată când utilizarea acestui format este benefică pentru mine este atunci când datele trebuie să fie sortate ca șiruri. Formatul ISO este sortabil ca atare, în timp ce celelalte nu. Dacă trebuie să aveți compatibilitate cross-browser, fie specificați fusul orar, fie utilizați un format de șir compatibil.

Codul nou Date ('12/4/2013 '). ToString () trece prin următoarea pseudo-transformare internă: