получить часовой пояс клиента из браузера [дубликат]

147

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

Автоматическое определение часового пояса с помощью JavaScript

Обнаружение часового пояса в JavaScript

Конфуций
источник
onlineaspect.com/2007/06/08/…
Ленар Хойт
8
Я написал jsTimezoneDetect, на который вы ссылаетесь выше, и я считаю, что он максимально приближен к чистому кроссбраузерному javascript (без геолокации и поиска IP).
Джон Ниландер,

Ответы:

86

Посмотрите на эту страницу репозитория, это полезно

загрузите jstz.min.js и добавьте функцию на свою html-страницу

<script language="javascript">
    function getTimezoneName() {
        timezone = jstz.determine()
        return timezone.name();
    }
</script>

и вызовите эту функцию из тега отображения

Гражданин Грузии
источник
14
TL; DR Теперь мы можем использовать Intl.DateTimeFormat().resolvedOptions().timeZone(без IE11), как предлагает Уоллес.
Code4R7
213

Спустя полдесятилетия у нас есть для этого встроенный способ! Для современных браузеров я бы использовал:

const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(tz);

Это возвращает строку часового пояса IANA, но не смещение . Узнайте больше в справочнике MDN .

Таблица совместимости - по состоянию на март 2019 года работает для 90% браузеров, используемых во всем мире. Не работает в Internet Explorer .

Уоллес
источник
4
не работает в firefox: Intl.DateTimeFormat().resolvedOptions().timeZone->undefined
Tomas Tomecek
3
Firefox и IE, похоже, не поддерживают это свойство :( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Уоллес,
6
Intl.DateTimeFormat().resolvedOptions().timeZoneвернет ожидаемое значение, начиная с Firefox 52: kangax.github.io/compat-table/esintl/…
июлен
Как использовать эту форму? В скрытом значении, как предлагается на сайте developer.mozilla.org/en-US/docs/Web/HTML/Element/input/… ?
hendry
7
Теперь работает в Firefox
Дастин
77

Часто, когда люди ищут «часовые пояса», достаточно просто «смещения UTC». например, их сервер находится в UTC + 5, и они хотят знать, что их клиент работает в UTC-8 .


В простом старом javascript (new Date()).getTimezoneOffset()/60вернет текущее количество часов смещения от UTC.

Стоит отметить возможную "ошибку" в знаке getTimezoneOffset()возвращаемого значения (из документации MDN) :

Смещение часового пояса - это разница в минутах между временем по Гринвичу и местным временем. Обратите внимание: это означает, что смещение положительное, если местный часовой пояс отстает от UTC, и отрицательное, если оно впереди. Например, для часового пояса UTC + 10: 00 (австралийское восточное стандартное время, владивостокское время, стандартное время чаморро) будет возвращено -600.


Однако я рекомендую вам использовать day.js для кода Javascript, связанного с датой и временем. В этом случае вы можете получить смещение UTC в формате ISO 8601, запустив:

> dayjs().format("Z")
"-08:00"

Вероятно, стоит упомянуть, что клиент может легко сфальсифицировать эту информацию.

(Примечание: этот ответ изначально рекомендовал https://momentjs.com/ , но dayjs - более современная альтернатива меньшего размера.)

Крис В.
источник
33
Возможно, стоит отметить, что смещение и часовой пояс не обязательно одно и то же.
Dex
9
Как бы вы применили DST только со смещением? В тех областях смещение неправильное пол года. IMO часовой пояс более точен.
Savageman
4
Летнее время является частью смещения в любой момент времени. Центральноевропейское время зимой - UTC + 01: 00. Однако, когда применяется летнее время, CET - это UTC + 02: 00, как сейчас в Дании, где я нахожусь.
Герт Сёндерби
1
вот почему getTimezoneOffset () нужна дата для работы - она ​​добавит летнее время, действующее на тот момент.
OsamaBinLogin
2
смещение неточно при переходе на летнее время.
Грег Л.
51

На данный момент лучшим вариантом, вероятно, будет jstz, как предлагается в ответе mbayloon .

Для полноты картины следует упомянуть, что на подходе есть стандарт: Intl . Вы уже можете увидеть это в Chrome:

> Intl.DateTimeFormat().resolvedOptions().timeZone
"America/Los_Angeles"

(На самом деле это не соответствует стандарту, что является еще одной причиной придерживаться библиотеки)

Йоханнес Хофф
источник
1
Intl выглядит стабильно во всем, кроме Safari. caniuse.com/#feat=internationalization
Майкл Коул,
2
@MichaelCole Соответствующие реализации Intlдолжны возвращаться undefinedдля timeZoneсвойства, если вы не указали вручную часовой пояс при создании DateTimeFormat. Chrome отклоняется от стандарта, вместо этого возвращая системный часовой пояс; это то, что использует ответ Йоханнеса, но также то, почему он сказал, что «на самом деле не соответствует стандарту».
Крис Джестер-Янг,
20
К вашему сведению - стандартом теперь является Intl.DateTimeFormat (). ResolvedOptions (). TimeZone
Nederby
4

Вот jsfiddle

Он обеспечивает сокращение часового пояса текущего пользователя.

Вот пример кода

var tz = jstz.determine();
console.log(tz.name());
console.log(moment.tz.zone(tz.name()).abbr(new Date().getTime()));
Пушкарь Ньюаскар
источник
1
Для отображения даты, как May 22 2015 03:45 PM CDT я использовал console.log(moment(now).format('MMM DD YYYY hh:mm A') + ' ' + moment.tz.zone(tz.name()).abbr(now.getTime()));
αƞjiβ
5
Ваша скрипка больше не работает и выдает ошибки в консоли.
Saumil
2

Я использовал подход, аналогичный подходу, принятому Джошем Фрейзером , который определяет смещение времени браузера от UTC и распознает ли он DST или нет (но несколько упрощено из его кода):

var ClientTZ = {
    UTCoffset:  0,          // Browser time offset from UTC in minutes
    UTCoffsetT: '+0000S',   // Browser time offset from UTC in '±hhmmD' form
    hasDST:     false,      // Browser time observes DST

    // Determine browser's timezone and DST
    getBrowserTZ: function () {
        var self = ClientTZ;

        // Determine UTC time offset
        var now = new Date();
        var date1 = new Date(now.getFullYear(), 1-1, 1, 0, 0, 0, 0);    // Jan
        var diff1 = -date1.getTimezoneOffset();
        self.UTCoffset = diff1;

        // Determine DST use
        var date2 = new Date(now.getFullYear(), 6-1, 1, 0, 0, 0, 0);    // Jun
        var diff2 = -date2.getTimezoneOffset();
        if (diff1 != diff2) {
            self.hasDST = true;
            if (diff1 - diff2 >= 0)
                self.UTCoffset = diff2;     // East of GMT
        }

        // Convert UTC offset to ±hhmmD form
        diff2 = (diff1 < 0 ? -diff1 : diff1) / 60;
        var hr = Math.floor(diff2);
        var min = diff2 - hr;
        diff2 = hr * 100 + min * 60;
        self.UTCoffsetT = (diff1 < 0 ? '-' : '+') + (hr < 10 ? '0' : '') + diff2.toString() + (self.hasDST ? 'D' : 'S');

        return self.UTCoffset;
    }
};

// Onload
ClientTZ.getBrowserTZ();

При загрузке выполняется ClientTZ.getBrowserTZ()функция, которая устанавливает:

  • ClientTZ.UTCoffset к смещению времени браузера от UTC в минутах (например, CST составляет -360 минут, что составляет -6,0 часов от UTC);
  • ClientTZ.UTCoffsetTна смещение в форме '±hhmmD'(например, '-0600D'), где суффикс Dдля DST и Sдля стандартного (не-DST);
  • ClientTZ.hasDST (истинно или ложно).

Значение ClientTZ.UTCoffsetуказывается в минутах, а не в часах, поскольку в некоторых часовых поясах почасовые смещения дробные (например, +0415).

Его цель ClientTZ.UTCoffsetT- использовать его в качестве ключа в таблице часовых поясов (здесь не приводится), например, для раскрывающегося <select>списка.

Дэвид Р. Триббл
источник
Похоже, он всегда будет возвращать "D", если наблюдается переход на летнее время. И почему разница всего в пять месяцев? Неужто Ян и Июль будут работать надежнее?
Мэтт
@Matt - Да, вы можете использовать 7-1июль вместо июня. Я не уверен, действительно ли это имеет значение, поскольку я сомневаюсь, что существуют региональные схемы летнего времени, которые не включают июнь.
Дэвид Р. Триббл
2

Вот версия, которая хорошо работает в сентябре 2020 года с использованием fetch и https://worldtimeapi.org/api

fetch("https://worldtimeapi.org/api/ip")
  .then(response => response.json())
  .then(data => console.log(data.timezone,data.datetime,data.dst));

mplungjan
источник
1
Это работает, но мы должны знать, что у него нет SLA, никаких гарантий и т.д .: worldtimeapi.org/pages/faqs
Энрике Завалета
-17

Нет. Единого надежного пути нет и не будет. Вы действительно думали, что можете доверять клиенту?

Флориан Маргейн
источник
24
Чтобы уточнить: часы клиента могут быть установлены неправильно, или они могут злонамеренно заставить вас думать, что они находятся в другом часовом поясе, чем настоящий. Если вы собираетесь использовать часовой пояс клиента, не делайте этого ни для чего важного.
Райан Кинал,
8
-1 за потенциально вводящий в заблуждение ответ, но не пояснение.
Doug S
6
Да, в своем приложении я могу доверять клиенту. Если клиент был неправильно настроен или имеет ошибку, это на моих пользователях.
Майкл Коул
3
Я действительно согласен с Флорианом. Надежный метод? Вроде. Надежные данные? Определенно нет.
Роб
4
Вопрос не говорит о том, как будут использоваться данные. Например, он не говорит, что обнаруженный часовой пояс когда-либо будет отправлен на сервер. Поэтому замечание о доверии неуместно, если данные используются исключительно локально.
дольмен