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?


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"

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.