Pytanie Przetwarzanie dat w javascript różni się od Safari i Chrome


Mam następujący kod

var c = new Date(Date.parse("2011-06-21T14:27:28.593Z"));
console.log(c);

W Chrome poprawnie drukuje datę na konsoli. W Safari to nie wyszło. Kto jest poprawny, a co ważniejsze, jaki jest najlepszy sposób poradzić sobie z tym?


44
2018-06-21 14:44


pochodzenie


Obaj dają mi Tue Jun 21 2011 10:27:28 GMT-0400 (Eastern Daylight Time) - Robert
Jesteś pewien. jsfiddle.net/A26Gu uruchom na Safari Wersja 5.0.4 (6533.20.27) daje mi wynik w konsoli "Nieprawidłowa data" - bradgonesurfing
Dlaczego dwa razy tworzysz obiekt Date? Jaka jest twoja definicja poprawności? Możesz użyć metody "Date.toISOString ()". Ale pamiętaj: nie jest obsługiwany przez starsze przeglądarki. - Wolfgang Kuehn
Hmm, dziwne ... Po prostu uruchomiłem to w konsoli, nie zawracałem sobie głowy tworzeniem strony. To działało w konsoli, kiedy podniosłem JSFiddle, nie robiąc nic, ale każda inna strona zwróciła NaN. Używam także wersji 5.0.5 (7533.21.1) - Robert
JavaScript Date obsługuje 2 strefy czasowe, UTC i lokalną z systemu operacyjnego. Nie możesz być pewien, że lokalna strefa czasowa jest ustawiona poprawnie. A ponieważ JavaScript jest stroną klienta, nie można naprawdę ufać, że robi coś poprawnego - nawet nie parsuje dat. Wszelkie obliczenia krytyczne aplikacji powinny być wykonywane po stronie serwera. - Erik


Odpowiedzi:


Naprawdę nie możesz używać Date.parse. Proponuję użyć: new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )

Aby podzielić ciąg, możesz spróbować

var s = '2011-06-21T14:27:28.593Z';
var a = s.split(/[^0-9]/);
//for (i=0;i<a.length;i++) { alert(a[i]); }
var d=new Date (a[0],a[1]-1,a[2],a[3],a[4],a[5] );
alert(s+ " "+d);

81
2018-06-21 14:52



Te ciągi dat pochodzą z serwera. Jeśli masz sposób, aby przeanalizować je w osobnych elementach, byłbym bardziej niż szczęśliwy, aby usłyszeć. - bradgonesurfing
Chciałbym użyć funkcji podziału: javascript.about.com/od/hintsandtips/a/javascriptsplit.htm - Erik
użycie podziału dodanego do odpowiedzi - Erik
Działa to tylko wtedy, gdy daty podane są w czasie lokalnym. Usuwa strefę czasową i stosuje lokalne. Przykład: jesteś w strefie czasowej -0500, którą przesyłasz o 11 rano, powinieneś wrócić o 6 rano, ale zamiast tego wrócisz o 11 rano. - dlsso
W odróżnieniu od tego, ta odpowiedź ignoruje strefę czasową. Bierze ciąg z offsetem 00:00 ("Z") i analizuje go tak, jakby był lokalny. Powinno się użyć Date.UTC. - RobG


Staram się unikać Date.parse, zgodnie z innymi odpowiedziami na to pytanie. Wydaje się, że nie jest to przenośny sposób na rzetelne radzenie sobie z datami.

Zamiast tego użyłem czegoś podobnego do poniższej funkcji. Wykorzystuje jQuery do odwzorowania tablicy łańcuchów na tablicę liczbową, ale jest to całkiem łatwa zależność do usunięcia / zmiany. Uwzględniam również to, co uważam za rozsądne, domyślne, aby umożliwić ci parsowanie 2007-01-09 i 2007-01-09T09:42:00 używając tej samej funkcji.

function dateFromString(str) {
  var a = $.map(str.split(/[^0-9]/), function(s) { return parseInt(s, 10) });
  return new Date(a[0], a[1]-1 || 0, a[2] || 1, a[3] || 0, a[4] || 0, a[5] || 0, a[6] || 0);
}

13
2018-02-23 12:38



Bardzo miły żart. - Bingy


Sprawdziłem to w kilku przeglądarkach, i tak, safari wraca invalid date. Nawiasem mówiąc, nie musisz używać Date.parse tutaj, właśnie new Date([datestring]) też będzie działać. Safari ewidentnie wymaga więcej formatowania dostarczanego datownika. Jeśli zastąpisz "-" przez "/", usuń T i wszystko po kropce (.593Z), to da ci poprawną datę. Ten kod jest testowany i działa w Safari

var datestr = '2011-06-21T14:27:28.593Z'.split(/[-T.]/);
var safdat = new Date( datestr.slice(0,3).join('/')+' '+datestr[3] );

Lub za pomocą String.replace(...):

new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/(\..*|\+.*/,""))

8
2018-06-21 15:48



Powoduje to utratę strefy czasowej i ułamków sekundy wynikowego obiektu Date. Sądzę, że na końcu możesz dodać dodatkowy kod, aby ponownie dodać te komponenty. - Tim Tisdall
Dziękuję, to wystarczy i zadziałało. - Daniel Sokolowski
Nawias w trzecim wyrażeniu nie jest potrzebny: new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/\..*|\+.*/,"")) - steevee


Skończyło się na tym, że korzystałem z biblioteki, aby to zrównoważyć:

http://zetafleet.com/blog/javascript-dateparse-for-iso-8601

Po włączeniu tej biblioteki możesz użyć tego kodu, aby utworzyć nową datę:

var date = new Date(Date.parse(datestring));

Nasz projekt nie korzystał z milisekundowych specyfikatorów, ale nie sądzę, że spowoduje to problem.


5
2017-09-13 21:18





Mój podobny problem został spowodowany przez Safari, który nie wiedział, jak odczytać strefę czasową w formacie strefy czasowej RFC 822. Udało mi się to naprawić, używając formatu ISO 8601. Jeśli masz kontrolę nad formatem daty, pracuję z SimpleDateFormat języka Java "yyyy-MM-dd'T'HH: mm: ss.sssXXX", który generuje dla mnie np. "2018-02-06T20: 00: 00.000 + 04: 00". Z jakiegokolwiek powodu Safari nie może odczytać "2018-02-06T20: 00: 00.000 + 0400", zauważ brak dwukropka w formacie strefy czasowej.

// Works
var c = new Date("2018-02-06T20:00:00.000+04:00"));
console.log(c);

// Doesn't work
var c = new Date("2018-02-06T20:00:00.000+0400"));
console.log(c);

4
2018-03-06 19:21





Używam następującej funkcji do analizowania dat w strefie czasowej. Działa dobrze zarówno w przeglądarce Chrome, jak i Safari:

function parseDate(date) {
  const parsed = Date.parse(date);
  if (!isNaN(parsed)) {
    return parsed;
  }

  return Date.parse(date.replace(/-/g, '/').replace(/[a-z]+/gi, ' '));
}

console.log(parseDate('2017-02-09T13:22:18+0300'));  // 1486635738000 time in ms


2
2018-02-10 03:47



To najbezpieczniejszy sposób na zrobienie tego. Chyba powinieneś zmienić ostatnią zamianę na coś podobnego /[a-z]+/gi, aby dopasować się do szerszej publiczności, np. daty z UTC zamiast tylko T. - Narayon
@Narayon dzięki za uwagę, zmieniłem odpowiedź. - Londeren


Próbowałem przekonwertować datę, obcinając ją i parsując ją w ten sposób, działa dobrze na safari i ios.

var dateString = "2016-01-22T08:18:10.000+0000";
 var hours = parseInt(dateString.split("+")[1].substr("0","2"));
 var mins = parseInt(dateString.split("+")[1].substr("2"));
 var date = new Date(dateString.split("+")[0]);
 date.setHours(date.getHours()-hours);
 date.setMinutes(date.getMinutes()-mins);

1
2018-01-27 05:07





Zamiast używać "Z" na końcu łańcucha daty, można dodać przesunięcie strefy czasowej lokalnego klienta. Prawdopodobnie będziesz potrzebować metody, która ją wygeneruje:

let timezoneOffset = () => {
    let date = new Date(),
        timezoneOffset = date.getTimezoneOffset(),
        hours = ('00' + Math.floor(Math.abs(timezoneOffset/60))).slice(-2),
        minutes = ('00' + Math.abs(timezoneOffset%60)).slice(-2),
        string = (timezoneOffset >= 0 ? '-' : '+') + hours + ':' + minutes;
    return string;
}

Wynik końcowy byłby następujący:

var c = new Date("2011-06-21T14:27:28.593" + timezoneOffset());


0
2018-04-27 19:55



Nieprawidłowa data w Safari ... - Mirko