Несоответствие часового пояса moment.js

Я форматирую данную дату, используя момент. Следующее ведет себя по-разному в разных часовых поясах:

moment(new Date("2016" + "-" + "06" + "-01").toISOString()).format('MMMM YYYY')

Это дает мне May 2016 в часовом поясе Америки / Денвер и June 2016 в Азии / Карачи. Я проверил, изменив часовой пояс браузера на разные часовые пояса. Так должно быть June 2016 в обоих.

Когда я меняю формат в new Date() использовать косую черту вместо дефисов, как показано ниже, это дает мне правильный результат в обеих часовых поясах, т.е. May 2016,

moment(new Date("2016" + "/" + "06" + "/01").toISOString()).format('MMMM YYYY')

Кажется, что обе строки являются допустимыми ISO-строками, что может вызвать эту несогласованность?

1 ответ

Решение

Короткий ответ на ваш вопрос заключается в том, что синтаксический анализатор для даты javascript не работает таким образом, который имеет смысл для всех. Вместо этого вы должны просто использовать парсер Moment, чтобы получить желаемый результат. Разбор дат таким способом, который имеет смысл, составляет примерно 50% от причины, по которой этот момент существует. Если вы исключите вызов даты и используете Moment для анализа вашей даты, вы заметите, что следующий код будет отображаться в июне 2016 года в любом браузере, поскольку ваша строка будет интерпретироваться как местное время, если вы используете конструктор Moment по умолчанию:

moment('2016-06-01').format()

Если вы хотите использовать вместо этого косые черты, это будет:

moment('2016/06/01', 'YYYY/MM/DD').format()

См. Руководство по синтаксическому анализу момента для получения дополнительной информации о том, как момент интерпретирует времена с его различными методами конструктора.

Длинный ответ заключается в том, что когда вы передаете строку в формате ISO8601, которая является датой только в конструктор дат JavaScript, она будет интерпретировать эту строку как UTC. Поскольку в дневное время для Денвера выбрано значение UTC -6, а для Карачи - время UTC +5, тогда момент отображает эту временную метку как местное время, и вы видите результат, который вы делаете. Вы можете наблюдать следующее:

var a = new Date('2016-06-01'); 
a.toISOString();
"2016-06-01T00:00:00.000Z"

Обратите внимание, что 'Z' в вышеуказанной временной метке указывает, что это UTC, поскольку toISOString всегда возвращает временную метку UTC. Эта отметка времени - июнь в Карачи, потому что Карачи опережает UTC, а май в Денвере, потому что Денвер отстает от UTC.

Соблюдайте это также:

var a = new Date('2016-06-01T00:00'); 
a.toISOString();
"2016-06-01T05:00:00.000Z"

Если я добавлю время в строку, оно будет интерпретироваться как местное время. Поскольку 1 января моим часовым поясом был UTC-5, точка на мировой шкале времени соответственно на пять часов опережает строку, которую я пропустил.

Поведение, которое вы видите - интерпретировать 2016-06-01 как UTC, но 2016-06-01T00:00 как локальное, на самом деле является попыткой покрыть технические долги в браузерах. Это было сделано стандартным поведением в 7-м издании спецификации ECMA 262, поэтому ожидайте, что это не изменится. Смотрите также эту ссылку.

Альтернативно, когда вы используете косые черты (2016/06/01), используемая вами реализация JS выбирает интерпретацию этого формата как местного времени, так как он не соответствует ни одному из форматов в стандарте ECMA. Это НЕ правильный формат ISO8601. Очень важно отметить, что это поведение зависит от конкретной реализации и будет различным в разных браузерах / средах. Стандарт ECMA не определяет поведение для анализа этого формата даты. Другие браузеры могут анализировать эту строку другими способами.

Как общий совет, не используйте анализатор дат JavaScript. Это не работает правильно. Вы можете использовать Moment.js, одного из немногих конкурентов, или вручную анализировать строки. Все это лучшие варианты.

Другие вопросы по тегам