moment.js - UTC дає неправильну дату


94

Чому UTC. moment.js завжди відображає неправильну дату. Наприклад, з консолі розробника chrome:

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

Обидва вони повернуть "17.07.2013", чому він повертається 17-м замість 18-го , що було передано.

Але якщо я використовую momentjs без utc:

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

Я повертаюся до "2013-07-18" , чого я також очікую, використовуючи moment.js UTC.

Чи означає це, що ми не можемо отримати правильну дату при використанні moment.js UTC?


4
Я не думаю, що вам потрібно toString()після format()(це вже повертає рядок).
alex

Відповіді:


159

За замовчуванням MomentJS аналізує за місцевим часом. Якщо вказано лише рядок дати (без часу), час за замовчуванням - опівночі.

У своєму коді ви створюєте локальну дату, а потім перетворюєте її в часовий пояс UTC (насправді, це робить екземпляр моменту переходом у режим UTC ), тому при форматуванні він переміщується (залежно від вашого місцевого часу) вперед або назад.

Якщо місцевим часовим поясом є UTC + N (N - додатне число), і ви проаналізували рядок лише для дати, ви отримаєте попередню дату.

Ось кілька прикладів, щоб проілюструвати це (мій зсув за місцевим часом UTC + 3 під час літнього часу):

>>> 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)"

Якщо ви хочете, щоб рядок дати та часу інтерпретувався як UTC, вам слід чітко це сказати:

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

або, як зазначає Метт Джонсон у своїй відповіді, ви можете ( і, мабуть, слід ) проаналізувати його як дату UTC, спочатку використовуючи moment.utc()та включивши рядок формату як другий аргумент, щоб запобігти неоднозначності.

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

Щоб піти навпаки і перетворити дату UTC на місцеву дату, ви можете скористатися local()методом таким чином:

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

Велике дякую. Отже, в основному, я завжди повинен вказувати час, використовуючи UTC, або передавати UTC, як у вашому другому підході.
brg

Або це, або дотримуйтесь місцевого часового поясу. Якщо ви надсилаєте час із сервера, ви можете виразити їх як позначку часу Unix (X) або як рядки в певному часовому поясі. Навіщо використовувати UTC замість місцевого часового поясу користувача, в будь-якому випадку (крім цілей надсилання нормалізованих даних на сервер)?
MasterAM

1
Майте на увазі, що new Date('07-18-2013 UTC')це не буде працювати в IE8, якщо вам все одно.
Дмитро Лазерка

2
Я боровся з цим так довго. Вони повинні дійсно добре пояснити це на своєму сайті, оскільки я припускаю, що це найпоширеніший випадок використання moment.js. Дуже дякую! Ти справді врятував мою шкіру!
WebWanderer

цей код працює для мене: [код] момент (strDate, 'DD / MM / YYYY h: mm A'). utc (strDate) .format ("YYYY-MM-DD HH: mm") [/ code]
Омар Ісаїд

36

Обидва Dateі momentаналізуватимуть вхідний рядок у локальному часовому поясі браузера за замовчуванням. Однак Dateіноді суперечить цьому питанню. Якщо рядок конкретно YYYY-MM-DDвикористовує дефіси , або якщо він є YYYY-MM-DD HH:mm:ss, він буде інтерпретувати це як місцевий час . На відміну від Date, momentзавжди буде послідовним щодо того, як він аналізується.

Правильний спосіб аналізу вхідного моменту як UTC у форматі, який ви надали, буде таким:

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

Зверніться до цієї документації .

Якщо ви хочете потім відформатувати його по-іншому для виводу, ви зробите це:

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

Вам не потрібно дзвонити toStringявно.

Зверніть увагу, що дуже важливо надати формат введення. Без нього дата, наприклад, 01-04-2013може бути оброблена як 4 січня, так і 1 квітня, залежно від налаштувань культури браузера.


Просто для навчання, у консолі: moment.utc ('18.07.2013 0:00 +0100', 'РРРР-ММ-ДД ЧЧ: мм') дає мені "18.07.2013 0:00 +0100 " Але те, що виплачується на jsfiddle при запуску, відрізняється: чт, 25 липня 2013 01:00:00 GMT + 0100 Зверніть увагу на 01:00:00 . Дякую.
brg

Виведення вихідного файлу momentна консолі не дуже корисне. Ви, мабуть, розглядаєте одне з його внутрішніх властивостей. Слід відформатувати його перед перевіркою результатів. Наприклад moment.utc().format()або moment().format().
Метт Джонсон-Пінт,

Як дата, так і момент проаналізують вхідний рядок у місцевому часовому поясі браузера за замовчуванням. Я зараз на EDT. new Date('2010-12-12')дає мені Date {Sat Dec 11 2010 19:00:00 GMT-0500 (Eastern Daylight Time)}в FF 38.0.5. Просто для контекстуалізації того, що саме означає "за місцевим часом" - у цьому випадку, схоже, це означає, " Dateприпустимо, що рядок без часового поясу знаходиться в UTC і буде аналізувати місцевий час". d.getUTCDate()= 12and d.getDate()=11
ruffin

1
Так, є деякі винятки. ES5 (більшість сучасних браузерів) буде інтерпретувати дати з дефісами як UTC, але майже все інше інтерпретується як місцевий час. ES6 змінює цю поведінку, щоб інтерпретувати той самий рядок, що і місцевий час. Я оновив відповідь.
Метт Джонсон-Пінт,

Так, так, щойно натрапив на це в MDN, сказавши саме це ( '2012-12-12'це UTC b / c, це у форматі ISO, але 'December 12, 2012'навіть '2012/12/12'аналізується з місцевим часовим поясом у ES5), але ви мене побили. Настільки великий, що ES6 робить їх усіх місцевими [він насмішкувато сказав]. Дати - це біль, (c) Поява дат
крафен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.