Работа с разными часовыми поясами в Javascript - PullRequest
0 голосов
/ 10 декабря 2018

Я работаю над облачным приложением, которое активно работает со значениями даты и времени для пользователей по всему миру.

Рассмотрим сценарий на JavaScript, где моя машина находится в Индии (GMT + 05:30), и я должен отобразить часы, работающие в часовом поясе Калифорнии (GMT-08: 00).

В этом случае мне нужно получить новый объект даты,

let india_date = new Date()

добавить значение смещения часового пояса,

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

добавить значение смещения часового пояса Калифорнии,

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

и, наконец,объект даты.

let california_date: Date = new Date(california_ms)

Есть ли способ напрямую работать с часовыми поясами такого типа без необходимости конвертировать значения снова и снова?

Ответы [ 4 ]

0 голосов
/ 11 декабря 2018

new Date создает объект Date со значением времени, которое является UTC.Если вы можете гарантировать поддержку опции timeZone , равной toLocaleString (например, корпоративная среда с контролируемой SOE), вы можете использовать ее для создания метки времени в любом часовом поясе и в любом формате, ноэто может быть немного утомительно.Поддержка на общем веб-сайте может отсутствовать.В этом случае библиотека предпочтительнее, если вам нужно, чтобы она работала надежно.

Например, чтобы получить значения для Калифорнии, вы можете использовать toLocaleString и "America / Los_Angeles" для опции timeZone :

var d = new Date();

// Use the default implementation format
console.log(d.toLocaleString(undefined, {timeZone:'America/Los_Angeles'}));

// Customised format
var weekday = d.toLocaleString(undefined, {weekday:'long', timeZone:'America/Los_Angeles'});
var day = d.toLocaleString(undefined, {day:'numeric', timeZone:'America/Los_Angeles'});
var month = d.toLocaleString(undefined, {month:'long', timeZone:'America/Los_Angeles'});
var year = d.toLocaleString(undefined, {year:'numeric', timeZone:'America/Los_Angeles'});
var hour = d.toLocaleString(undefined, {hour:'numeric',hour12: false, timeZone:'America/Los_Angeles'});
var minute = d.toLocaleString(undefined, {minute:'2-digit', timeZone:'America/Los_Angeles'});
var ap = hour > 11? 'pm' : 'am';
hour = ('0' + (hour % 12 || 12)).slice(-2);

console.log(`The time in Los Angeles is ${hour}:${minute} ${ap} on ${weekday}, ${day} ${month}, ${year}`);

Получить название часового пояса немного сложнее, его трудно получить без другой информации.

0 голосов
/ 10 декабря 2018

JavaScript Date объекты хранят дату и время в UTC, но метод toString() вызывается автоматически, когда дата представляется в виде текстового значения, которое отображает дату и время вместный часовой пояс браузера.Поэтому, когда вы хотите преобразовать дату и время в часовой пояс, отличный от вашего местного времени, вы действительно конвертируете из UTC в этот часовой пояс (не из своего местного часового пояса в другой часовой пояс).

Если вашВариант использования ограничен конкретными браузерами, и вы можете гибко форматировать (поскольку браузеры могут различаться по способу отображения форматов строк даты), тогда вы можете использовать toLocaleString(), но такие браузеры, как Edge, Androidwebview и т. д. не полностью поддерживают параметры locales и options.

В следующем примере задается и локаль, и часовой пояс для вывода даты в локальном формате, который может варьироваться от браузера к браузеру.

let dt = new Date();

let kolkata = dt.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });
let la = dt.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' });

console.log('Kolkata:', kolkata);
// Kolkata: 19/3/2019, 7:36:26 pm
console.log('Los Angeles:', la);
// Los Angeles: 3/19/2019, 7:06:26 AM

Вы также можете использовать Moment.js и Часовой пояс момента для преобразования даты и времени в часовой пояс, отличный от вашего местногочасовой пояс.Например:

let dt = moment();

let kolkata = dt.tz('Asia/Kolkata').format()
let la = dt.tz('America/Los_Angeles').format()

console.log(kolkata);
// 2019-03-19T19:37:11+05:30
console.log(la);
// 2019-03-19T07:07:11-07:00
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>
0 голосов
/ 10 декабря 2018

Во-первых, давайте поговорим о коде в вашем вопросе.

let india_date = new Date()

Вы назвали эту переменную india_date, но объект Date будет отражать только Индию, есликод запускается на компьютере с часовым поясом Индии.Если он запущен на компьютере с другим часовым поясом, он будет отражать этот часовой пояс.Имейте в виду, что внутри объекта Date отслеживается только временная метка на основе UTC.Местный часовой пояс применяется при вызове функций и свойств, для которых требуется местное время, а не при создании объекта Date.

добавление значения смещения часового пояса

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

Этот подход неверен.getTime() уже возвращает временную метку на основе UTC.Вам не нужно добавлять ваше локальное смещение.(также сокращение UTC, а не UTS.)

Теперь добавьте значение смещения часового пояса Калифорнии

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

Опять добавление смещения некорректно.Кроме того, в отличие от Индии, в Калифорнии наблюдается переход на летнее время, поэтому часть года смещение будет 480 (UTC-8), а часть года смещение будет 420 (UTC-7).Любая функция, такая как getCaliforniatimezoneOffsetMS, должна иметь метку времени, передаваемую в качестве параметра, чтобы она действовала.

и, наконец, объект даты

let california_date: Date = new Date(california_ms)

Когдаконструктору Date передается числовая метка времени, она должна быть в формате UTC.Передавая эту california_ms метку времени, вы просто выбираете другой момент времени.Вы не можете изменить поведение Date объекта, чтобы заставить его использовать другой часовой пояс, просто добавляя или вычитая смещение.Он по-прежнему будет использовать местный часовой пояс, в котором он выполняется, для любой функции, для которой требуется местное время, например .toString() и др.

Существует только один сценарий, в котором имеет смысл подобная настройка, котораяэто техника, известная как «смена эпох».Временная метка регулируется для смещения базовой эпохи от обычного 1970-01-01T00:00:00Z, что позволяет использовать преимущества UTC-функций Date объекта (таких как getUTCHours и другие).Подвох заключается в том, что после сдвига вы не сможете использовать какие-либо функции локального времени для этого объекта Date или передавать его чему-либо еще, что ожидает, что объект Date будет нормальным.Сдвиг эпохи, сделанный правильно - это то, что делает библиотеки такими, как Moment.js . Здесь - еще один пример правильной смены эпох.

Но в вашем примере вы смещаетесь (дважды по ошибке), а затем используете объект Date, как если бы он был нормальным и не смещался.Это может привести только к ошибкам, очевидным для часового пояса, показанного в выводе toString, и будет возникать математически вблизи любых DST-переходов местного часового пояса и предполагаемого целевого часового пояса.В общем, вы не хотите использовать этот подход.

Вместо этого прочитайте мой ответ на Как инициализировать дату JavaScript для определенного часового пояса. Здесь перечислены ваши варианты.Спасибо.

0 голосов
/ 10 декабря 2018

Что ж, вам действительно приходится конвертировать в любое время, когда вы хотите изменить отображение, но это не так плохо, как вы думаете.

Во-первых, сохраняйте все время как UTC.Вероятно, используется миллисекундный формат , например Date.UTC().

Во-вторых, выполняйте все манипуляции / сравнение, используя эту хранимую информацию.

В-третьих, если у вашего облачного приложения есть API, API должен также говорить только в терминах UTC, хотя вы могли быпредоставьте строку ISO, если вы предпочитаете это MS, или если вы ожидаете, что клиенты справятся с этим лучше.

В-четвертых, и наконец, только в пользовательском интерфейсе вы должны выполнить окончательное преобразование в локальную строку даты / времени либо с помощью описываемого вами метода, либо с использованием библиотеки, такой как momentjs

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...