Формат даты в определенном часовом поясе

177

Я использую Moment.js для анализа и форматирования дат в своем веб-приложении. Как часть объекта JSON, мой внутренний сервер отправляет даты в виде количества миллисекунд от эпохи UTC (смещение Unix).

Разбор дат в определенном часовом поясе прост - просто добавьте идентификатор часового пояса RFC 822 в конец строки перед анализом:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Но как мне отформатировать дату в определенном часовом поясе ?

Я хочу получать стабильные результаты независимо от текущего времени браузера, но не хочу отображать даты в формате UTC.

quietmint
источник
2
Момент пока не поддерживает это, но они работают над этим. github.com/timrwood/moment/pull/671
Бен
5
Это должно просто работать. Если вы передаете момент времени строку времени, которая включает в себя желаемое смещение, тогда оно должно сохранить это смещение и отобразить местное время, как указано, вместо того, чтобы автоматически настраиваться на местное время браузера. Если бы я хотел, чтобы он адаптировался к местному времени браузера, то я бы дал время UTC вместо того, чтобы явно указать смещение для использования. Я имею в виду ... Я даю это явное смещение, почему оно в основном поглощает это и делает свое собственное преобразование в смещение браузеров. Страшный дизайн.
Триынко
Смещения @Triynko подвержены переходу на летнее время, поэтому он не всегда работает должным образом.
Pinkpanther
1
Что-то связанное с этим, я хочу напечатать время в определенном формате, например, 15 марта 2018 года, но не могу найти строку формата для этого. Универсальный DD MMM, YYYYне работает, когда я использую его как moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). Может кто-то указать мне в документации, где я могу найти все ключи для форматирования времени при использовании этого API.
pRmdk
@PramodKumar Что не так? Это дает "15 Feb, 2018". Вы хотели использовать форматную строку DD MMMM, YYYYдля получения "15 February, 2018"?
тихая мята

Ответы:

248

Как указано в ответе Манто , .utcOffset()это предпочтительный метод с момента 2.9.0. Эта функция использует реальное смещение от UTC, а не обратное смещение (например, -240 для Нью-Йорка во время летнего времени). Смещенные строки типа «+0400» работают так же, как и раньше:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

Более старый .zone()как сеттер был объявлен устаревшим в Moment.js 2.9.0. Он принял строку, содержащую идентификатор часового пояса (например, «-0400» или «-04: 00» для -4 часов) или число, представляющее минуты после UTC (например, 240 для Нью-Йорка во время летнего времени).

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

Чтобы работать с именными часовыми поясами вместо числовых смещений, включите часовой пояс Moment и используйте .tz()вместо него:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
quietmint
источник
У меня были проблемы с этим из-за ошибки «TypeError: У объекта 240 нет метода« format »». Я понял, что зона доступна только как установщик на версии 2.1.0 и выше Moment.js (и я был на более старой версии). Спасибо!
Мелинда Уэзерс
5
@ebi По умолчанию он уже использует часовой пояс браузера. Чтобы получить доступ к смещению часового пояса браузера, используйте .zone()в качестве получателя, который возвращает минуты от UTC (например, возвращает 300 для Нью-Йорка в течение стандартного времени).
тихая мята
1
@EricCope Нет, не совсем. Тем не менее, вы можете использовать, .tz("America/Phoenix")если вы включаете momentjs.com/timezone . Я обновил ответ с примером.
тихая мята
1
Обратите внимание, что использование смещения не будет работать должным образом, если часовой пояс имеет разные смещения из-за перехода на летнее время.
Pinkpanther
1
Будет ли .utcOffset () автоматически управлять летним временем? например, когда я устанавливаю UTC +1 CET зимой, будет ли ставка UTC +2 CEST в летнее время? Потому что это делает его пригодным для использования или нет!
haemse
61

Использовать момент-часовой пояс

moment(date).tz('Europe/Berlin').format(format)

Прежде чем вы сможете получить доступ к определенному часовому поясу, вам необходимо загрузить его так (или использовать альтернативные методы, описанные здесь )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Филипп Нужный
источник
Я не думаю, что момент tz был доступен, когда был задан вопрос, но я думаю, что это может быть путь. В настоящее время я работаю над похожей проблемой со всеми временными метками, хранящимися как UTC в MySQL, но для просмотра в определенной зоне, зависящей от конфигурации пользователя, а не от часового пояса клиента.
nickdnk
47

В нескольких ответах уже упоминается, что момент-часовой пояс - это путь к названному часовому поясу. Я просто хочу прояснить кое-что об этой библиотеке, что довольно смущает меня. Есть разница между этими двумя утверждениями:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

Предполагая, что часовой пояс не указан в дате, переданной в:

Первый код принимает дату и предполагает, что часовым поясом является тот, который был передан. Второй принимает дату, принимает часовой пояс из браузера, а затем изменяет время и часовой пояс в соответствии с переданным часовым поясом.

Пример:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

Мой часовой пояс +5 от UTC. Таким образом, в первом случае он не изменяется и устанавливает дату и время для часового пояса utc.

Во втором случае предполагается, что переданная дата находится в -5, а затем преобразуется в UTC, и поэтому она выплевывает дату «2018-07-18T00: 00: 00Z».

ПРИМЕЧАНИЕ. Параметр формата действительно важен. Если пропущенный момент может вернуться к классу Date, это может привести к непредсказуемому поведению


Предполагая, что часовой пояс указан в дате, переданной в:

В этом случае они оба ведут себя одинаково


Несмотря на то, что теперь я понимаю, почему это так, я подумал, что это довольно запутанная особенность, которую стоит объяснить.

Никола Педретти
источник
1
момент (...). tz не является функцией
K - токсичность в SO растет.
5
Вы установили момент-часовой пояс?
Никола Педретти
Есть ли способ вернуть проанализированный и преобразованный момент назад без форматирования? Например, если я хочу форматировать по-разному, не анализируя все заново.
jEremyB
Спасибо за разъяснение: у меня возникли проблемы при установке часового пояса, отличного от часового пояса браузера пользователя, и это была именно та проблема.
Робин Шааф
20

.zone () устарела, и вы должны использовать вместо нее utcOffset:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
Манто
источник
8

У меня была такая же проблема с Moment.js. Я установил момент-часовой пояс, но проблема не была решена. Затем я сделал только то, что здесь показано, установил часовой пояс, и он работает как шарм:

moment(new Date({your_date})).zone("+08:00")

Большое спасибо!

facundofarias
источник
16
Вы не должны использовать new Date()конструктор. Момент предоставляет все, что вам когда-либо нужно для анализа дат. Смотрите парсинг документов.
тихая мята
Да, но если я этого не сделаю, я получаю предупреждение от Момента, что это устарело из-за чего-то подобного
facundofarias
7
Предупреждение означает, что Moment внутренне возвращается к тому, что вы делаете (используете new Date()внутренне), но это несовместимо с браузерами . Вместо этого вы должны использовать предполагаемый формат в качестве второго аргумента. Пример: moment("12-25-1995", "MM-DD-YYYY").
спокойная мята
4

Просто пришёл этот вопрос, и, поскольку у меня возникла та же проблема, я бы просто опубликовал результаты, которые придумали

при синтаксическом анализе вы можете обновить смещение (т.е. я анализирую данные (1.1.2014) и мне нужна только дата, 1 января 2014 года. В GMT + 1 я получу 31.12.2013. Поэтому сначала я смещаю значение.

moment(moment.utc('1.1.2014').format());

Ну, мне пригодилась поддержка часовых поясов

В

Бард Ротцер
источник
-7

Вы можете попробовать это,

Здесь вы можете получить дату на основе часового пояса клиента (браузера).

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

Регулярное выражение в основном возвращает значение смещения.

Ура !!

K.Karthik
источник
Обычно момент дает вам все, что вам нужно. Вам никогда не нужно ничего подобного обычай.
Махеш Самудра