Nieprawidłowa data w safari

155
 alert(new Date('2010-11-29'));

chrome, ff nie ma z tym problemów, ale safari krzyczy „nieprawidłowa data”. Czemu ?

edycja: ok, zgodnie z komentarzami poniżej, użyłem parsowania ciągów i spróbowałem tego:

alert(new Date('11-29-2010')); //doesn't work in safari
alert(new Date('29-11-2010')); //doesn't work in safari
alert(new Date('2010-29-11')); //doesn't work in safari

edytuj Mar 22 2018 : Wygląda na to, że ludzie wciąż tu lądują - Dzisiaj użyłbym momentlub date-fnsi skończę z tym. Date-fns jest również bardzo bezbolesny i lekki.

Shrinath
źródło
Tylko dla innych spojrzeń na ten sam problem: Skończyło się na DateJS, który ogólnie rozwiązał mój problem. Zobacz zaakceptowaną odpowiedź po szczegóły.
Shrinath
2
użyj momentu.js, aby przeanalizować znacznik czasu. Zwłaszcza w przypadku sieci wieloplatformowych
Ming Yuen,
1
To jest stare pytanie. Począwszy od ECMAScript 2015, ciągi zawierające tylko datę ISO 8601 są analizowane jako UTC. Jednak nadal mogą istnieć starsze przeglądarki, które albo w ogóle go nie analizują, albo traktują je jako lokalne.
RobG

Odpowiedzi:

167

Wzorzec yyyy-MM-ddnie jest oficjalnie obsługiwanym formatem dla Datekonstruktora. Wydaje się, że Firefox to obsługuje, ale nie licz na to, że inne przeglądarki zrobią to samo.

Oto kilka obsługiwanych ciągów:

  • MM-dd-yyyy
  • rrrr / MM / dd
  • MM / dd / rrrr
  • MMMM dd, yyyy
  • MMM dd, yyyy

DateJS wydaje się dobrą biblioteką do analizowania niestandardowych formatów dat.

Edycja : właśnie sprawdzono standard ECMA-262 . Cytując z sekcji 15.9.1.15:

Format ciągu daty i godziny

ECMAScript definiuje format wymiany ciągów dla dat i godzin w oparciu o uproszczenie rozszerzonego formatu ISO 8601. Format jest następujący: RRRR-MM-DDTHH: mm: ss.sssZ Gdzie pola są następujące:

  • RRRR to cyfry dziesiętne roku w kalendarzu gregoriańskim.
  • „-” (hyphon) pojawia się w ciągu dosłownie dwa razy.
  • MM to miesiąc roku od 01 (styczeń) do 12 (grudzień).
  • DD to dzień miesiąca od 01 do 31.
  • „T” pojawia się dosłownie w ciągu, aby wskazać początek elementu czasu.
  • HH to liczba pełnych godzin, które upłynęły od północy w postaci dwóch cyfr dziesiętnych.
  • „:” (dwukropek) występuje w ciągu znaków dosłownie dwa razy.
  • mm to liczba pełnych minut od początku godziny w postaci dwóch cyfr dziesiętnych.
  • ss to liczba pełnych sekund od początku minuty w postaci dwóch cyfr dziesiętnych.
  • „.” (kropka) pojawia się dosłownie w ciągu.
  • sss to liczba pełnych milisekund od początku sekundy, wyrażona w postaci trzech cyfr dziesiętnych. Oboje "." a pole milisekund można pominąć.
  • Z to przesunięcie strefy czasowej określone jako „Z” (dla UTC) lub „+” lub „-”, po którym następuje wyrażenie czasu gg: mm

Ten format obejmuje formularze zawierające tylko datę:

  • RRRR
  • RRRR-MM
  • RRRR-MM-DD

Obejmuje również formularze tylko czasowe z dołączonym opcjonalnym przesunięciem strefy czasowej:

  • THH: mm
  • THH: mm: ss
  • THH: mm: ss.sss

Uwzględniono również „daty i godziny”, które mogą stanowić dowolną kombinację powyższych.

Wygląda więc na to, że RRRR-MM-DD jest zawarty w standardzie, ale z jakiegoś powodu Safari go nie obsługuje.

Aktualizacja : po przejrzeniu dokumentacji datejs i użyciu jej, twój problem powinien zostać rozwiązany za pomocą takiego kodu:

var myDate1 = Date.parseExact("29-11-2010", "dd-MM-yyyy");
var myDate2 = Date.parseExact("11-29-2010", "MM-dd-yyyy");
var myDate3 = Date.parseExact("2010-11-29", "yyyy-MM-dd");
var myDate4 = Date.parseExact("2010-29-11", "yyyy-dd-MM");
darioo
źródło
4
Format ISO8601 jest używany w piątej edycji standardu ECMAScript i nie jest jeszcze szeroko obsługiwany, najbezpieczniejszy sposób korzystania z IMO, przeanalizuj datę ręcznie :(
CMS
1
To było bardzo pomocne koleś… Dziękuję… :) W końcu skończyło się na używaniu datejów do formatowania.
Shrinath
dla przyszłych, pamiętaj, że chociaż datejs jest fantastyczny pod wieloma względami, nie rozwiązuje wszystkich problemów z formatowaniem daty, szczególnie w przypadku safari. jest to PITA, ale najlepiej zrobić to ręcznie, jeśli nadal masz problemy.
totalNotLizards
@darioo Wypróbowałem więc twoją odpowiedź w następujący sposób: "var start = Date.parseExact (timestamp," RRRR-DD-MM HH: mm: SS ");" sygnatura czasowa to „2016-01-28 00:00:00”. Jednak teraz pojawia się błąd, że „Date.parseExact nie jest funkcją”. Czy wiesz, co się tutaj dzieje?
threxx
5
Mój podobny problem był spowodowany tym, że Safari nie wiedziało, 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, mam to, pracując z „rrrr-MM-dd'T'HH: mm: ss.sssXXX”, który tworzy np. „2018-02-06T20: 00: 00.000 + 00: 00”. Z jakiegoś powodu Safari nie może odczytać „2018-02-06T20: 00: 00.000 + 0000”, zwróć uwagę na brak dwukropka w formacie strefy czasowej.
Olmstov
224

Dla mnie implementacja nowej biblioteki tylko dlatego, że Safari nie może tego zrobić poprawnie, to za dużo, a wyrażenie regularne to przesada. Oto oneliner :

console.log (new Date('2011-04-12'.replace(/-/g, "/")));
Elzo Valugi
źródło
Gdyby ukośnik był tylko moim problemem, to „zaakceptowałbym” Twoją odpowiedź (chociaż był to mój jedyny cel, kiedy zadałem to pytanie). Teraz, gdy znalazłem dateJS, zaimplementowałem format MMM DD, RRRR, aby był bardziej przyjazny dla użytkownika !!!
Shrinath,
13
Ta jedna linia pomocy była idealna dla moich potrzeb! Dzięki!
Cyril N.
4
Dla mnie to też było dość proste. Nie mogę uwierzyć, że Safari nie lubi - ale ten sam format z \\ działa. Dzięki @Elzo i Shrinath za opublikowanie pytania
Pete
1
Myślę, że to najlepsza odpowiedź, którą zwykle zapominam / - / g zamiast „-”
Jacek Pietal
12
brawa za niestosowanie biblioteki.
lharby
55

Miałem podobny problem. Date.Parse("DATESTRING")działał na Chrome (wersja 59.0.3071.115), ale nie na Safari (wersja 10.1.1 (11603.2.5))

Safari:

Date.parse("2017-01-22 11:57:00")
NaN

Chrom:

Date.parse("2017-01-22 11:57:00")
1485115020000

Rozwiązaniem, które zadziałało, było zastąpienie spacji w ciągu dateString przez "T". (przykład dateString.replace(/ /g,"T"):)

Safari:

Date.parse("2017-01-22T11:57:00")
1485086220000

Chrom:

Date.parse("2017-01-22T11:57:00")
1485115020000

Zwróć uwagę, że odpowiedź z przeglądarki Safari jest o 8 godzin (28800000 ms) krótsza niż odpowiedź widoczna w przeglądarce Chrome, ponieważ Safari zwróciło odpowiedź w lokalnym TZ (czyli o 8 godzin za czasem UTC)

Aby uzyskać oba czasy w tej samej TZ

Safari:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

Chrom:

Date.parse("2017-01-22T11:57:00Z")
1485086220000
nizantz
źródło
Lub jeśli nie chcesz, aby obie daty były takie same w Safari i Chrome, możesz użyć new Date(year, month, date, hours, minutes, seconds, milliseconds)konstruktora. Przeanalizuj datę ciągu do tablicy jego składników, aby użyć tych składników w konstruktorze. @nizantz byłoby wspaniale, gdybyś pomyślał, że taki przykład można dodać do Twojej odpowiedzi.
h3dkandi
Niezbyt przydatne, ponieważ otrzymujesz datę w UTC, a nie w czasie lokalnym.
Jonas Ęppelgran
1
U dateString.replace(/ /g,"T")mnie zadziałała ta magiczna linia kodu. :)
Mazdak Shojaie
replace (/ - / g, '/')
Jack Hu
11

Wykorzystuję chwilę, aby rozwiązać problem. Na przykład

var startDate = moment('2015-07-06 08:00', 'YYYY-MM-DD HH:mm').toDate();
liwp_Stephen
źródło
10

Aby rozwiązanie działało w większości przeglądarek, należy utworzyć obiekt daty w tym formacie

(year, month, date, hours, minutes, seconds, ms)

na przykład:

dateObj = new Date(2014, 6, 25); //UTC time / Months are mapped from 0 to 11
alert(dateObj.getTime()); //gives back timestamp in ms

działa dobrze z IE, FF, Chrome i Safari. Nawet starsze wersje.

Centrum deweloperów IE: obiekt daty (JavaScript)

Mozilla Dev Network: Data

Luxx
źródło
6

przekonwertuj ciąg na Date fromat (musisz znać strefę czasową serwera)

new Date('2015-06-16 11:00:00'.replace(/\s+/g, 'T').concat('.000+08:00')).getTime()  

gdzie +08: 00 = strefa czasowa z serwera

Anja Ishmukhametova
źródło
To nie uwzględnia czasu letniego. Przesunięcie TZ może się zmieniać i zależy od samej daty (i godziny).
costa
5

Miałem ten sam problem, a potem wykorzystałem moment. J. Problem zniknął.

Tworząc moment z łańcucha, najpierw sprawdzamy, czy ciąg pasuje do znanych formatów ISO 8601, a następnie wracamy do nowej daty (ciągu), jeśli nie zostanie znaleziony znany format.

Ostrzeżenie: obsługa analizowania ciągów przez przeglądarkę jest niespójna. Ponieważ nie ma specyfikacji, które formaty powinny być obsługiwane, to, co działa w niektórych przeglądarkach, nie będzie działać w innych przeglądarkach.

Aby uzyskać spójne wyniki analizowania czegokolwiek innego niż ciągi ISO 8601, należy użyć ciągu + format.

na przykład

var date= moment(String);
Sampath
źródło
3

Chociaż możesz mieć nadzieję, że przeglądarki będą obsługiwać ISO 8601 (lub jego podzbiory tylko z datą), tak nie jest. Wszystkie znane mi przeglądarki (przynajmniej w językach amerykańskich / angielskich, których używam) są w stanie przeanalizować okropny MM/DD/YYYYformat amerykański .

Jeśli masz już części daty, możesz zamiast tego spróbować użyć Date.UTC () . Jeśli tego nie zrobisz, ale musisz użyć YYYY-MM-DDformatu, sugeruję użycie wyrażenia regularnego do przeanalizowania elementów, które znasz, a następnie przekazania ich do Date.UTC().

Phrogz
źródło
Wydaje
1

Użyj poniższego formatu, będzie działać we wszystkich przeglądarkach

var year = 2016;
var month = 02;           // month varies from 0-11 (Jan-Dec)
var day = 23;

month = month<10?"0"+month:month;        // to ensure YYYY-MM-DD format
day = day<10?"0"+day:day;

dateObj = new Date(year+"-"+month+"-"+day);

alert(dateObj); 

// Twój wynik będzie wyglądał następująco: „Wed Mar 23 2016 00:00:00 GMT + 0530 (IST)”

// Zauważ, że będzie to aktualna strefa czasowa w tym przypadku oznaczona przez IST, aby przekonwertować na strefę czasową UTC, którą możesz dołączyć

alert(dateObj.toUTCSting);

// Twoje wyniki wyglądają teraz następująco: „Wt, 22 Mar 2016 18:30:00 GMT”

Zauważ, że teraz dateObj pokazuje czas w formacie GMT, zwróć także uwagę, że data i czas zostały odpowiednio zmienione.

Funkcja „toUTCSting” pobiera odpowiedni czas na południku Greenwich. Osiąga się to poprzez ustalenie różnicy czasu między twoją bieżącą strefą czasową a strefą czasową Greenwich Meridian.

W powyższym przypadku czas przed konwersją wynosił 00:00 godzin i minut 23 marca 2016 roku. A po konwersji z GMT + 0530 (IST) godzin na GMT (zasadniczo odejmuje 5,30 godziny od podanego znacznika czasu w tym przypadek) oznacza godzinę 18:30 w dniu 22 marca 2016 roku (dokładnie 5:30 za pierwszym razem).

Ponadto, aby przekonwertować dowolny obiekt daty na znacznik czasu, którego możesz użyć

alert(dateObj.getTime());

// wynik będzie wyglądał podobnie do tego „1458671400000”

Dałoby to unikalny znacznik czasu

Abhay Aradhya
źródło
1

Co powiesz na przejęcie Datez fix-date ? Brak zależności, min + gzip = 280 B

kenberkeley
źródło
1

Najlepszym sposobem na to jest użycie następującego formatu:

new Date(year, month, day, hours, minutes, seconds, milliseconds)
var d = new Date(2018, 11, 24, 10, 33, 30, 0);

Jest to obsługiwane we wszystkich przeglądarkach i nie powoduje żadnych problemów. Pamiętaj, że miesiące są zapisywane od 0 do 11.

Daniël Brito
źródło
Działa dobrze w Safari i Chrome, ale nadal ma problemy z Firefoksem. Safari: var date = new Date (2018,06, 08,19,17) Sun Jul 08 2018 19:17:00 GMT + 0800 (+08) Chrome: var date = new Date (2018,06, 08,19, 17) niedz. 08 lipca 2018 19:17:00 GMT + 0800 (czas malezyjski) Firefox: var date = new Date (2018,06,08,19,17) Data 2018-07-08T11: 17: 00.000Z
Biranchi
0

Ten sam problem, który pojawił się w Safari i został rozwiązany poprzez wstawienie tego na stronie internetowej

 <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> 

Mam nadzieję, że zadziała również w Twojej sprawie

Dzięki

Yasir Shabbir Choudhary
źródło
Jak myślisz, dlaczego to zadziała? Przyjrzałem się skryptowi i wydaje się, że nie zastępuje on metod w obiekcie Date. Poszedłem tutaj: polyfill.io/v3/url-builder i wydaje się, że nie ma nic o analizowaniu dat.
costa
0

Jak @nizantz wspomniał wcześniej, używanie Date.parse () nie działało dla mnie w Safari. Po krótkiej analizie dowiedziałem się, że właściwość lastDateModified obiektu File jest przestarzała i nie jest już obsługiwana przez Safari. Użycie właściwości lastModified obiektu File rozwiązało moje problemy. Z pewnością nie podoba mi się, gdy w Internecie zostaną znalezione złe informacje.

Dziękuję wszystkim, którzy przyczynili się do powstania tego postu, który pomógł mi podążać ścieżką, której potrzebowałem, aby poznać mój problem. Gdyby nie te informacje, prawdopodobnie nigdy nie rozwiązałbym problemu z głównym źródłem. Może to pomoże komuś innemu w podobnej sytuacji.

S. Costello
źródło
0

Mam również ten sam problem w przeglądarce Safari

var date = new Date("2011-02-07");
console.log(date) // IE you get ‘NaN’ returned and in Safari you get ‘Invalid Date’

Oto rozwiązanie:

var d = new Date(2011, 01, 07); // yyyy, mm-1, dd  
var d = new Date(2011, 01, 07, 11, 05, 00); // yyyy, mm-1, dd, hh, mm, ss  
var d = new Date("02/07/2011"); // "mm/dd/yyyy"  
var d = new Date("02/07/2011 11:05:00"); // "mm/dd/yyyy hh:mm:ss"  
var d = new Date(1297076700000); // milliseconds  
var d = new Date("Mon Feb 07 2011 11:05:00 GMT"); // ""Day Mon dd yyyy hh:mm:ss GMT/UTC 
venkatskpi
źródło
0

Nie jest to najlepsze rozwiązanie, chociaż po prostu wyłapuję błąd i odsyłam aktualną datę. Osobiście czuję, że nie chcę rozwiązywać problemów z Safari, jeśli użytkownicy chcą używać przeglądarki zgodnej ze standardami, muszą żyć z dziwactwami.

function safeDate(dateString = "") {
  let date = new Date();
  try {
    if (Date.parse(dateString)) {
      date = new Date(Date.parse(dateString))
    }
  } catch (error) {
    // do nothing.
  }
  return date;
}

Sugerowałbym, aby Twój backend wysyłał daty ISO.

AndrewMcLagan
źródło
Z całym szacunkiem, kiedy masz na myśli, że użytkownicy muszą używać przeglądarki, dla której napisałeś kod, wygląda to źle w ogólnym sensie. Zależy to również od naszych przypadków użycia i docelowych odbiorców - jeśli witryna jest budowana na potrzeby masowego użytku, wspieralibyśmy przynajmniej IE10. Jestem pewien, że ktoś w stwardnieniu rozsianym myślał to samo, kiedy projektował / kodował dla przeglądarki internetowej. Wszyscy wiemy, jak się teraz o tym mówi.
Shrinath
-1

użyj formatu „dd / mm / rrrr”. Na przykład: - nowa data („02/28/2015”). Działa dobrze we wszystkich przeglądarkach.

Ravi S
źródło