Определите часовой пояс пользователя

Существует ли стандартный способ определения часового пояса пользователя на веб-странице веб-сервером?

Возможно, из HTTP-заголовка или части user-agent строки?

Ответов (25)

Простой способ сделать это - использовать:

new Date().getTimezoneOffset();

Вот как я это делаю. Это установит часовой пояс PHP по умолчанию на местный часовой пояс пользователя. Просто вставьте следующее вверху всех своих страниц:

<?php
session_start();

if(!isset($_SESSION['timezone']))
{
    if(!isset($_REQUEST['offset']))
    {
    ?>
        <script>
        var d = new Date()
        var offset= -d.getTimezoneOffset()/60;
        location.href = "<?php echo $_SERVER['PHP_SELF']; ?>?offset="+offset;
        </script>
        <?php   
    }
    else
    {
        $zonelist = array('Kwajalein' => -12.00, 'Pacific/Midway' => -11.00, 'Pacific/Honolulu' => -10.00, 'America/Anchorage' => -9.00, 'America/Los_Angeles' => -8.00, 'America/Denver' => -7.00, 'America/Tegucigalpa' => -6.00, 'America/New_York' => -5.00, 'America/Caracas' => -4.30, 'America/Halifax' => -4.00, 'America/St_Johns' => -3.30, 'America/Argentina/Buenos_Aires' => -3.00, 'America/Sao_Paulo' => -3.00, 'Atlantic/South_Georgia' => -2.00, 'Atlantic/Azores' => -1.00, 'Europe/Dublin' => 0, 'Europe/Belgrade' => 1.00, 'Europe/Minsk' => 2.00, 'Asia/Kuwait' => 3.00, 'Asia/Tehran' => 3.30, 'Asia/Muscat' => 4.00, 'Asia/Yekaterinburg' => 5.00, 'Asia/Kolkata' => 5.30, 'Asia/Katmandu' => 5.45, 'Asia/Dhaka' => 6.00, 'Asia/Rangoon' => 6.30, 'Asia/Krasnoyarsk' => 7.00, 'Asia/Brunei' => 8.00, 'Asia/Seoul' => 9.00, 'Australia/Darwin' => 9.30, 'Australia/Canberra' => 10.00, 'Asia/Magadan' => 11.00, 'Pacific/Fiji' => 12.00, 'Pacific/Tongatapu' => 13.00);
        $index = array_keys($zonelist, $_REQUEST['offset']);
        $_SESSION['timezone'] = $index[0];
    }
}

date_default_timezone_set($_SESSION['timezone']);

//rest of your code goes here
?>

Легко, просто используйте getTimezoneOffset функцию JavaScript вот так:

-new Date().getTimezoneOffset()/60;

Попробуйте этот код PHP:

<?php
    $ip = $_SERVER['REMOTE_ADDR'];
    $json = file_get_contents("http://api.easyjquery.com/ips/?ip=" . $ip . "&full=true");
    $json = json_decode($json,true);
    $timezone = $json['LocalTimeZone'];
?>

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

>>> var timezone = jstz.determine();
>>> timezone.name(); 
"Europe/London"

https://github.com/pellepim/jstimezonedetect

Я до сих пор не видел здесь подробного ответа, который получает часовой пояс. Вам не нужно геокодировать по IP-адресу, использовать PHP (смеется) или неправильно угадывать смещение.

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

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

Теперь, чтобы получить часовой пояс с помощью javascript, вы можете использовать это:

>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.

Однако мне было проще просто использовать этот надежный плагин, который возвращает часовой пояс в формате Olsen:

https://github.com/scottwater/jquery.detect_timezone

Чтобы отправить смещение часового пояса в виде HTTP-заголовка в запросах AJAX с помощью jQuery

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
    }
});

Вы также можете сделать что - то подобное , чтобы получить фактическое время название зоны, используя moment.tz.guess(); от http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/

Не используйте IP-адрес для окончательного определения местоположения (и, следовательно, часового пояса) - это потому, что с NAT, прокси-серверами (которые становятся все более популярными) и VPN, IP-адреса не обязательно реалистично отражают фактическое местоположение пользователя, но местоположение, в котором серверы, реализующие эти протоколы, постоянно находятся.

Подобно тому, как коды городов США больше не используются для поиска пользователя телефона, учитывая популярность переносимости номеров.

IP-адрес и другие методы, показанные выше, полезны для предложения значения по умолчанию, которое пользователь может настроить / исправить.

С JavaScript и PHP это просто:

Несмотря на то, что пользователь может испортить свои внутренние часы и / или часовой пояс, лучший способ, который я нашел до сих пор, чтобы получить смещение, остается new Date().getTimezoneOffset(); . Это неинвазивно, не вызывает головной боли и избавляет от необходимости полагаться на третьих лиц.

Скажем, у меня есть таблица, users которая содержит поле date_created int(13) для хранения временных меток Unix;

Предполагая , что клиент creates a new account, данные принимаются post, и мне нужно с Отметка времени Unix клиента, а не сервера. insert/update date_created column

Поскольку timezoneOffset необходим во время вставки / обновления, он передается как дополнительный элемент $ _POST, когда клиент отправляет форму, что устраняет необходимость хранить его в сеансах и / или файлах cookie, а также никаких дополнительных обращений к серверу.

var off = (-new Date().getTimezoneOffset()/60).toString();//note the '-' in front which makes it return positive for negative offsets and negative for positive offsets
var tzo = off == '0' ? 'GMT' : off.indexOf('-') > -1 ? 'GMT'+off : 'GMT+'+off;

Скажем, сервер получает tzo как $_POST['tzo'] ;

$ts = new DateTime('now', new DateTimeZone($_POST['tzo']);
$user_time = $ts->format("F j, Y, g:i a");//will return the users current time in readable format, regardless of whether date_default_timezone() is set or not.
$user_timestamp = strtotime($user_time);

Вставить / обновить date_created=$user_timestamp .

При получении date_created вы можете преобразовать метку времени следующим образом:

$date_created = // Get from the database
$created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever

Теперь этот пример может соответствовать first вашим потребностям, когда дело доходит до вставки метки времени ... Когда дело доходит до дополнительной метки времени или таблицы, вы можете подумать о том, чтобы вставить значение tzo в таблицу пользователей для дальнейшего использования или установить его. как сеанс или как файл cookie.

PS НО что делать, если пользователь путешествует и меняет часовые пояса. Войдите в систему в GMT + 4, быстро переместится в GMT-1 и снова войдет в систему. Последний вход будет в будущем.

Я думаю ... мы слишком много думаем.

Во-первых, поймите, что определение часового пояса в JavaScript несовершенно. Вы можете получить смещение местного часового пояса для определенной даты и времени, используя getTimezoneOffset экземпляр Date объекта, но это не совсем то же самое, что и полный часовой пояс IANA, как America/Los_Angeles .

Однако есть несколько вариантов, которые могут работать:

  • Большинство современных браузеров поддерживают часовые пояса IANA в своей реализации ECMAScript Internationalization API , поэтому вы можете сделать это:

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

Результатом является строка, содержащая настройку часового пояса IANA для компьютера, на котором выполняется код.

Поддерживаемые среды перечислены в таблице совместимости Intl . Разверните DateTimeFormat раздел и посмотрите на названную функцию resolvedOptions().timeZone defaults to the host environment .

  • Некоторые библиотеки, такие как Luxon, используют этот API для определения часового пояса с помощью таких функций, как luxon.Settings.defaultZoneName.

  • Если вам нужно поддерживать более широкий набор сред, например старые веб-браузеры, вы можете использовать библиотеку, чтобы сделать обоснованное предположение о часовом поясе. Они работают, сначала пробуя IntlAPI, если он доступен, а когда он недоступен, они опрашивают getTimezoneOffsetфункцию Dateобъекта для нескольких разных моментов времени, используя результаты для выбора подходящего часового пояса из внутреннего набора данных.

    Оба jsTimezoneDetect и момент-часовой пояс имеют эту функциональность.

      // using jsTimeZoneDetect
      var tzid = jstz.determine().name();
    
      // using moment-timezone
      var tzid = moment.tz.guess();
    

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

    Кроме того, эти библиотеки необходимо периодически обновлять, чтобы противодействовать тому факту, что многие старые реализации JavaScript знают только о текущем правиле перехода на летнее время для своего местного часового пояса. Подробнее об этом здесь.

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

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

Получение действительного имени часового пояса базы данных TZ в PHP - это двухэтапный процесс:

  1. С помощью JavaScript можно получить смещение часового пояса за считанные минуты getTimezoneOffset. Это смещение будет положительным, если местный часовой пояс отстает от UTC, и отрицательным, если он опережает. Таким образом, вы должны добавить к смещению противоположный знак.

    var timezone_offset_minutes = new Date().getTimezoneOffset();
    timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
    

    Передайте это смещение в PHP.

  2. В PHP преобразуйте это смещение в действительное имя часового пояса с помощью функции timezone_name_from_abbr .

    // Just an example.
    $timezone_offset_minutes = -360;  // $_GET['timezone_offset_minutes']
    
    // Convert minutes to seconds
    $timezone_name = timezone_name_from_abbr("", $timezone_offset_minutes*60, false);
    
    // America/Chicago
    echo $timezone_name;</code></pre>
    

Я написал об этом сообщение в блоге: Как определить часовой пояс пользователя в PHP . Он также содержит демонстрацию.

Вы можете сделать это на клиенте с моментальным часовым поясом и отправить значение на сервер; пример использования:

> moment.tz.guess()
"America/Asuncion"

Нет такого способа определить часовой пояс в реальном HTML-коде или любой user-agent строке, но вы можете сделать базовую функцию, получающую его с помощью JavaScript.

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

Однако вы можете попытаться получить фактический часовой пояс, также используя JavaScript с getTzimezoneOffset() функцией в Date разделе или просто new Date().getTimezoneOffset(); .

Я думаю, что @Matt Johnson-Pints это, безусловно, лучший вариант, и поиск CanIuse показывает, что сейчас он получил широкое распространение:

https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone

Однако одна из проблем - подумать, почему вы хотите знать часовой пояс. Потому что я думаю, что одна из вещей, которые упускают из виду большинство людей, - это то, что они могут измениться! Если пользователь путешествует со своим ноутбуком из Европы в Америку, если вы ранее сохранили его в базе данных, его часовой пояс теперь неверен (даже если пользователь на самом деле никогда не обновляет часовой пояс своих устройств). Это также проблема с @Mads Kristiansen ответом, потому что пользователи путешествуют - вы не можете полагаться на это как на данность.

Например, на моем ноутбуке с Linux отключен автоматический часовой пояс. Хотя время может обновлять мой часовой пояс, этого не происходит.

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

Пока нет HTTP-заголовков, которые сообщают о часовом поясе клиента, хотя было предложено включить его в спецификацию HTTP.

Если бы это был я, я бы, вероятно, попытался получить часовой пояс с помощью клиентского JavaScript, а затем отправить его на сервер с помощью Ajax или чего-то еще.

JavaScript - самый простой способ узнать местное время клиента. Я бы предложил использовать XMLHttpRequest для отправки обратно местного времени, и если это не удастся, вернуться к часовому поясу, обнаруженному на основе их IP-адреса.

Что касается геолокации, я использовал MaxMind GeoIP в нескольких проектах, и он работает хорошо, хотя я не уверен, предоставляют ли они данные о часовом поясе. Это услуга, за которую вы платите, и они ежемесячно обновляют вашу базу данных. Они предоставляют оболочки на нескольких веб-языках.

Самый популярный (== стандартный?) Способ определения часового пояса, который я видел, - это просто спросить самих пользователей. Если вашему веб-сайту требуется подписка, ее можно сохранить в данных профиля пользователя. Для анонимных пользователей даты могут отображаться как UTC, GMT или что-то в этом роде.

Я не пытаюсь быть умником. Просто иногда некоторые проблемы имеют более тонкие решения вне всякого программного контекста.

Кажется, вся магия в

visitortime.getTimezoneOffset()

Это круто, я не знал об этом. Это работает в Internet Explorer и т. Д.? Оттуда вы сможете использовать JavaScript для Ajax, устанавливать файлы cookie. Я бы, наверное, и сам пошел по пути печенья.

Однако вам нужно разрешить пользователю изменить его. Некоторое maxmind время назад мы пытались использовать геолокацию (через ), чтобы сделать это, и это было достаточно неправильно, чтобы этого не делать. Поэтому мы просто позволяем пользователю установить его в своем профиле и показываем уведомление пользователям, которые еще не установили свой профиль.

Если вы используете OpenID для аутентификации, Simple Registration Extension решит проблему для аутентифицированных пользователей (вам нужно будет преобразовать из tz в число).

Другой вариант - вывести часовой пояс из предпочтений страны пользовательского агента. Это несколько грубый метод (не работает для en-US), но дает хорошее приближение.

-new Date().getTimezoneOffset()/60;

The method getTimezoneOffset() will subtract your time from GMT and return the number of minutes. So if you live in GMT-8, it will return 480.

To put this into hours, divide by 60. Also, notice that the sign is the opposite of what you need - it's calculating GMT's offset from your time zone, not your time zone's offset from GMT. To fix this, simply multiply by -1.

Also note that w3school says:

The returned value is not a constant, because of the practice of using Daylight Saving Time.

Вот статья (с исходным кодом), в которой объясняется, как определять и использовать локализованное время в приложении ASP.NET (VB.NET, C#):

Пора

Короче говоря, описанный подход основан на getTimezoneOffset функции JavaScript , которая возвращает значение, сохраненное в файле cookie сеанса и используемое выделенным кодом для корректировки значений времени между GMT и местным временем. Приятно то, что пользователю не нужно указывать часовой пояс (код делает это автоматически). Это более сложный процесс (поэтому я ссылаюсь на статью), но предоставленный код делает его действительно простым в использовании. Я подозреваю, что вы можете преобразовать логику в PHP и другие языки (если вы понимаете ASP.NET).

С помощью date функции PHP вы получите дату и время сервера, на котором расположен сайт. Единственный способ получить время пользователя - использовать JavaScript.

Но я предлагаю вам сделать это, если для вашего сайта требуется регистрация, тогда лучший способ - попросить пользователя сделать регистрацию в качестве обязательного поля. Вы можете указать различные часовые пояса на странице регистрации и сохранить их в базе данных. После этого, если пользователь входит на сайт, вы можете установить часовой пояс по умолчанию для этого сеанса в соответствии с выбранным пользователем часовым поясом.

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

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

Ниже приведен сценарий для получения часового пояса пользователей с помощью PHP и JavaScript.

<?php
    #http://www.php.net/manual/en/timezones.php List of Time Zones
    function showclienttime()
    {
        if(!isset($_COOKIE['GMT_bias']))
        {
?>

            <script type="text/javascript">
                var Cookies = {};
                Cookies.create = function (name, value, days) {
                    if (days) {
                        var date = new Date();
                        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                        var expires = "; expires=" + date.toGMTString();
                    }
                    else {
                        var expires = "";
                    }
                    document.cookie = name + "=" + value + expires + "; path=/";
                    this[name] = value;
                }

                var now = new Date();
                Cookies.create("GMT_bias",now.getTimezoneOffset(),1);
                window.location = "<?php echo $_SERVER['PHP_SELF'];?>";
            </script>

            <?php

        }
        else {
          $fct_clientbias = $_COOKIE['GMT_bias'];
        }

        $fct_servertimedata = gettimeofday();
        $fct_servertime = $fct_servertimedata['sec'];
        $fct_serverbias = $fct_servertimedata['minuteswest'];
        $fct_totalbias = $fct_serverbias – $fct_clientbias;
        $fct_totalbias = $fct_totalbias * 60;
        $fct_clienttimestamp = $fct_servertime + $fct_totalbias;
        $fct_time = time();
        $fct_year = strftime("%Y", $fct_clienttimestamp);
        $fct_month = strftime("%B", $fct_clienttimestamp);
        $fct_day = strftime("%d", $fct_clienttimestamp);
        $fct_hour = strftime("%I", $fct_clienttimestamp);
        $fct_minute = strftime("%M", $fct_clienttimestamp);
        $fct_second = strftime("%S", $fct_clienttimestamp);
        $fct_am_pm = strftime("%p", $fct_clienttimestamp);
        echo $fct_day.", ".$fct_month." ".$fct_year." ( ".$fct_hour.":".$fct_minute.":".$fct_second." ".$fct_am_pm." )";
    }

    showclienttime();
?>

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

Вот более полный способ.

  1. Получить смещение часового пояса для пользователя
  2. Проверьте несколько дней на границах перехода на летнее время, чтобы определить, находятся ли они в зоне, где используется летнее время.

Ниже приводится отрывок:

function TimezoneDetect(){
    var dtDate = new Date('1/1/' + (new Date()).getUTCFullYear());
    var intOffset = 10000; //set initial offset high so it is adjusted on the first attempt
    var intMonth;
    var intHoursUtc;
    var intHours;
    var intDaysMultiplyBy;

    // Go through each month to find the lowest offset to account for DST
    for (intMonth=0;intMonth < 12;intMonth++){
        //go to the next month
        dtDate.setUTCMonth(dtDate.getUTCMonth() + 1);

        // To ignore daylight saving time look for the lowest offset.
        // Since, during DST, the clock moves forward, it'll be a bigger number.
        if (intOffset > (dtDate.getTimezoneOffset() * (-1))){
            intOffset = (dtDate.getTimezoneOffset() * (-1));
        }
    }

    return intOffset;
}

Получение TZ и DST из JS (через Way Back Machine)

Используя подход Unkwntech, я написал функцию с использованием jQuery и PHP. Это проверено и работает!

На странице PHP, где вы хотите использовать часовой пояс в качестве переменной, разместите этот фрагмент кода где-нибудь в верхней части страницы:

<?php
    session_start();
    $timezone = $_SESSION['time'];
?>

Будет прочитана переменная сеанса «время», которую мы сейчас создаем.

На этой же странице в теге <head> в первую очередь нужно включить jQuery:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>

Также в <head> под jQuery вставьте это:

<script type="text/javascript">
    $(document).ready(function() {
        if("<?php echo $timezone; ?>".length==0){
            var visitortime = new Date();
            var visitortimezone = "GMT " + -visitortime.getTimezoneOffset()/60;
            $.ajax({
                type: "GET",
                url: "http://example.org/timezone.php",
                data: 'time='+ visitortimezone,
                success: function(){
                    location.reload();
                }
            });
        }
    });
</script>

Возможно, вы заметили или не заметили, но вам нужно изменить URL-адрес на ваш реальный домен.

Последняя вещь. Вам, наверное, интересно, что такое timezone.php. Ну, это просто: (создайте новый файл с именем timezone.php и укажите на него указанным выше URL-адресом)

<?php
    session_start();
    $_SESSION['time'] = $_GET['time'];
?>

Если это работает правильно, он сначала загрузит страницу, выполнит JavaScript и перезагрузит страницу. После этого вы сможете прочитать переменную $ timezone и использовать ее в свое удовольствие! Он возвращает текущее смещение часового пояса UTC / GMT (GMT -7) или любой другой часовой пояс, в котором вы находитесь.

JavaScript:

function maketimus(timestampz)
{
    var linktime = new Date(timestampz * 1000);
    var linkday = linktime.getDate();
    var freakingmonths = new Array();

    freakingmonths[0]  = "jan";
    freakingmonths[1]  = "feb";
    freakingmonths[2]  = "mar";
    freakingmonths[3]  = "apr";
    freakingmonths[4]  = "may";
    freakingmonths[5]  = "jun";
    freakingmonths[6]  = "jul";
    freakingmonths[7]  = "aug";
    freakingmonths[8]  = "sep";
    freakingmonths[9]  = "oct";
    freakingmonths[10] = "nov";
    freakingmonths[11] = "dec";

    var linkmonthnum = linktime.getMonth();
    var linkmonth = freakingmonths[linkmonthnum];
    var linkyear = linktime.getFullYear();
    var linkhour = linktime.getHours();
    var linkminute = linktime.getMinutes();

    if (linkminute < 10)
    {
        linkminute = "0" + linkminute;
    }

    var fomratedtime = linkday + linkmonth + linkyear + " " +
                       linkhour + ":" + linkminute + "h";
    return fomratedtime;
}

Просто предоставьте этой функции свое время в формате временной метки Unix; JavaScript уже знает часовой пояс пользователя.

Нравится:

PHP:

echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';

Это всегда будет показывать время правильно в зависимости от часового пояса, установленного человеком на часах своего компьютера. Нет нужды ни у кого просить и сохранять по местам, слава богу!