moment.js - UTC podaje nieprawidłową datę

94

Dlaczego moment.js UTC zawsze pokazuje nieprawidłową datę. Na przykład z konsoli programisty Chrome:

moment(('07-18-2013')).utc().format("YYYY-MM-DD").toString()
// or
moment.utc(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Obaj zwrócą „2013-07-17”, dlaczego zwraca 17. zamiast 18. , które zostało przekazane.

Ale jeśli użyję momentjs bez utc:

moment(new Date('07-18-2013')).format("YYYY-MM-DD").toString()

Wracam „2013-07-18”, czego również oczekuję, korzystając z czasu UTC.js.

Czy to oznacza, że ​​nie możemy uzyskać prawidłowej daty, korzystając z czasu UTC w chwili.js?

brg
źródło
4
Myślę, że nie potrzebujesz toString()po format()(już zwraca ciąg).
Alex

Odpowiedzi:

159

Domyślnie MomentJS analizuje w czasie lokalnym. Jeśli podano tylko ciąg daty (bez godziny), domyślną godziną jest północ.

W swoim kodzie tworzysz lokalną datę, a następnie konwertujesz ją na strefę czasową UTC (w rzeczywistości powoduje ona przełączenie instancji momentu w tryb UTC ), więc po sformatowaniu jest przesuwana (w zależności od czasu lokalnego) do przodu lub wstecz.

Jeśli lokalna strefa czasowa to UTC + N (N jest liczbą dodatnią) i przeanalizujesz ciąg zawierający tylko datę, otrzymasz poprzednią datę.

Oto kilka przykładów ilustrujących to (moje lokalne przesunięcie czasu to UTC + 3 podczas czasu letniego):

>>> moment('07-18-2013', 'MM-DD-YYYY').utc().format("YYYY-MM-DD HH:mm")
"2013-07-17 21:00"
>>> moment('07-18-2013 12:00', 'MM-DD-YYYY HH:mm').utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 09:00"
>>> Date()
"Thu Jul 25 2013 14:28:45 GMT+0300 (Jerusalem Daylight Time)"

Jeśli chcesz, aby ciąg daty i czasu był interpretowany jako UTC, powinieneś o tym wyraźnie powiedzieć:

>>> moment(new Date('07-18-2013 UTC')).utc().format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

lub, jak wspomina Matt Johnson w swojej odpowiedzi, możesz ( i prawdopodobnie powinieneś ) przeanalizować ją jako datę UTC w pierwszej kolejności, używając moment.utc()i dołączając łańcuch formatu jako drugi argument, aby zapobiec niejednoznaczności.

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').format("YYYY-MM-DD HH:mm")
"2013-07-18 00:00"

Aby przejść na drugą stronę i przekonwertować datę UTC na datę lokalną, możesz użyć local()metody w następujący sposób:

>>> moment.utc('07-18-2013', 'MM-DD-YYYY').local().format("YYYY-MM-DD HH:mm")
"2013-07-18 03:00"
MasterAM
źródło
Wielkie dzięki. Zasadniczo powinienem zawsze przechodzić w czasie, używając UTC lub przechodząc w UTC, jak w drugim podejściu.
brg,
Albo to, albo trzymaj się lokalnej strefy czasowej. Jeśli wysyłasz czasy z serwera, możesz je wyrazić jako uniksowy znacznik czasu (X) lub jako ciągi znaków w określonej strefie czasowej. W każdym razie po co używać UTC zamiast lokalnej strefy czasowej użytkownika (z wyjątkiem wysyłania znormalizowanych danych na serwer)?
MasterAM,
1
Pamiętaj, że new Date('07-18-2013 UTC')to nie zadziała w IE8, jeśli Ci zależy.
Dzmitry Lazerka
2
Walczę z tym od tak dawna. Powinni naprawdę dobrze to wyjaśnić na swojej stronie, ponieważ zakładam, że jest to najczęstszy przypadek użycia momentu.js. Dziękuję bardzo! Naprawdę uratowałeś moją skórę!
WebWanderer
ten kod działa dla mnie: [kod] moment (strDate, 'DD / MM / RRRR h: mm A'). utc (strDate) .format ("RRRR-MM-DD GG: mm") [/ kod]
Omar Powiedziałem
36

Obie Datei momentdomyślnie przeanalizują ciąg wejściowy w lokalnej strefie czasowej przeglądarki. Jednak Dateczasami jest to niezgodne z tym względem. Jeśli ciąg znaków jest określony YYYY-MM-DDprzy użyciu łączników lub jeśli tak jest YYYY-MM-DD HH:mm:ss, zinterpretuje go jako czas lokalny . W przeciwieństwie do tego Date, momentzawsze będzie konsekwentnie analizować sposób.

Prawidłowy sposób analizowania momentu wejściowego jako UTC w podanym formacie wyglądałby tak:

moment.utc('07-18-2013', 'MM-DD-YYYY')

Zapoznaj się z tą dokumentacją .

Jeśli chcesz później sformatować go w inny sposób do wyjścia, wykonaj następujące czynności:

moment.utc('07-18-2013', 'MM-DD-YYYY').format('YYYY-MM-DD')

Nie musisz dzwonić toStringjawnie.

Zwróć uwagę, że bardzo ważne jest podanie formatu wejściowego. Bez tego randka jak01-04-2013 może zostać przetworzona jako 4 stycznia lub 1 kwietnia, w zależności od ustawień kultury przeglądarki.

Matt Johnson-Pint
źródło
Tak dla nauki, w konsoli: moment.utc ('2013-07-18 0:00 +0100', 'RRRR-MM-DD GG: mm') daje mi "2013-07-18 0:00 +0100 „ Ale to, co wyświetla się na jsfiddle po uruchomieniu, jest inne, to znaczy: czw. 25 lipca 2013 01:00:00 GMT + 0100 Zwróć uwagę na 01:00:00 . dzięki.
brg,
Wyprowadzanie surowego pliku momentna konsolę nie jest zbyt przydatne. Prawdopodobnie patrzysz na jedną z jego wewnętrznych właściwości. Powinieneś go sformatować przed sprawdzeniem wyników. Na przykład moment.utc().format()lub moment().format().
Matt Johnson-Pint,
Zarówno Data, jak i moment będą domyślnie analizować ciąg wejściowy w lokalnej strefie czasowej przeglądarki. Jestem teraz na EDT. new Date('2010-12-12')daje mi Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}w FF 38.0.5. Żeby tylko kontekstualizować, co dokładnie oznacza „w czasie lokalnym” - w tym przypadku wydaje się oznaczać, że Dateprzyjmie ciąg bez strefy czasowej w UTC i przeanalizuje go na czas lokalny”. d.getUTCDate()= 12i d.getDate()=11
ruffin
1
Tak, jest kilka wyjątków. ES5 (większość obecnych przeglądarek) będzie interpretować daty z łącznikami jako UTC, ale prawie wszystko inne jest interpretowane jako czas lokalny. ES6 zmienia to zachowanie, aby interpretować ten sam ciąg jako czas lokalny. Zaktualizowałem odpowiedź.
Matt Johnson-Pint
Ha, tak, właśnie natknąłem się na to w MDN, mówiąc dokładnie to ( '2012-12-12'to UTC b / c, jest w formacie ISO, ale 'December 12, 2012'nawet '2012/12/12'są analizowane z lokalną strefą czasową w ES5), ale pokonałeś mnie w tym. Tak wspaniale, że ES6 sprawia, że ​​wszystkie są lokalne [powiedział sarkastycznie]. Daty są uciążliwe, (c) Adwent dat
ruffin