Определить часовой пояс пользователя
Существует ли для веб-сервера стандартный способ определения часового пояса пользователя на веб-странице?
Возможно из заголовка HTTP или части user-agent
строка?
28 ответов
-new Date().getTimezoneOffset()/60;
Метод getTimezoneOffset()
вычтет ваше время из GMT и вернет количество минут. Так что если вы живете в GMT-8, он вернется 480.
Чтобы перевести это в часы, разделите на 60. Также обратите внимание, что знак противоположен тому, что вам нужно, - это расчет смещения GMT от вашего часового пояса, а не смещения вашего часового пояса от GMT. Чтобы это исправить, просто умножьте на -1.
Также обратите внимание, что w3school говорит:
Возвращаемое значение не является константой из-за практики использования летнего времени.
Самый популярный (== стандартный?) Способ определения часового пояса, который я видел вокруг, это просто опрос самих пользователей. Если ваш сайт требует подписки, это может быть сохранено в данных профиля пользователя. Для пользователей, не являющихся пользователями, даты могут отображаться в формате UTC, GMT или как-то так.
Я не пытаюсь быть умным человеком. Просто иногда у некоторых проблем есть более тонкие решения вне контекста программирования.
Пока нет заголовков HTTP, которые сообщали бы о часовом поясе клиентов, хотя было предложено включить его в спецификацию HTTP.
Если бы это был я, я бы, вероятно, попытался получить часовой пояс, используя клиентский JavaScript, а затем отправить его на сервер, используя Ajax или что-то еще.
Во-первых, следует понимать, что обнаружение часового пояса в JavaScript несовершенно. Вы можете получить смещение часового пояса для конкретной даты и времени, используя getTimezoneOffset
на примере Date
объект, но это не совсем то же самое, что полный часовой пояс IANA, как America/Los_Angeles
,
Есть несколько вариантов, которые могут работать, хотя:
Большинство современных браузеров поддерживают часовые пояса IANA при реализации API интернационализации ECMAScript, поэтому вы можете сделать это:
const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
В результате получается строка, содержащая настройку часового пояса IANA компьютера, на котором выполняется код.
Поддерживаемые среды перечислены в таблице совместимости Intl. Разверните
DateTimeFormat
раздел, и посмотрите на функцию с именемresolvedOptions().timeZone defaults to the host environment
,Если вам требуется поддержка более широкого набора сред, таких как старые веб-браузеры, вы можете использовать библиотеку, чтобы сделать обоснованное предположение о часовом поясе. Они работают, сначала пытаясь
Intl
API, если он доступен, и когда он недоступен, они опрашиваютgetTimezoneOffset
функцияDate
объект, для нескольких разных моментов времени, используя результаты, чтобы выбрать подходящий часовой пояс из внутреннего набора данных.Как jsTime zoneDetect, так и момент-время имеют эту функциональность.
// using jsTimeZoneDetect var tzid = jstz.determine().name(); // using moment-timezone var tzid = moment.tz.guess();
В обоих случаях результат можно рассматривать только как предположение. Предположение может быть правильным во многих случаях, но не во всех.
Кроме того, эти библиотеки должны периодически обновляться, чтобы противодействовать тому факту, что многие старые реализации JavaScript знают только текущее правило перехода на летнее время для своего местного часового пояса. Подробнее об этом здесь.
В конечном итоге, лучший подход - спросить пользователя о его часовом поясе. Укажите настройки, которые они могут изменить. Вы можете использовать один из приведенных выше вариантов, чтобы выбрать настройку по умолчанию, но не исключайте возможность отклонения от этого в своем приложении.
Существует также совершенно другой подход - не полагаться на настройку часового пояса на компьютере пользователя. Вместо этого, если вы можете собрать координаты широты и долготы, вы можете преобразовать их во временную зону одним из следующих способов. Это хорошо работает на мобильных устройствах.
JavaScript - это самый простой способ узнать местное время клиента. Я бы предложил использовать XMLHttpRequest для отправки назад по местному времени, а если это не удастся, вернуться к часовому поясу, обнаруженному на основе их IP-адреса.
Что касается геолокации, я использовал MaxMind GeoIP в нескольких проектах, и он работает хорошо, хотя я не уверен, предоставляют ли они данные о часовых поясах. Это услуга, за которую вы платите, и они ежемесячно обновляют вашу базу данных. Они предоставляют обертки на нескольких веб-языках.
Вот надежное решение JavaScript для определения часового пояса, в котором находится браузер.
>>> var timezone = jstz.determine();
>>> timezone.name();
"Europe/London"
Вот более полный путь.
- Получить смещение часового пояса для пользователя
- Протестируйте несколько дней на границах летнего времени, чтобы определить, находятся ли они в зоне, где используется летнее время.
Выдержка ниже:
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'];
?>
Это будет читать сессионную переменную "время", которую мы сейчас собираемся создать.
На той же странице, в
, вам нужно прежде всего включить jQuery:<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
Также в
, ниже 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) или любой другой часовой пояс, в котором вы находитесь.
Чтобы отправить смещение часового пояса в виде заголовка 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/
Не используйте IP-адрес для окончательного определения местоположения (и, следовательно, часового пояса)- это потому, что с NAT, прокси (все более популярными) и VPN, IP-адреса не обязательно реалистично отражают фактическое местоположение пользователя, но местоположение, в котором серверы, реализующие эти протоколы находятся.
Подобно тому, как коды США в США больше не используются для определения местоположения пользователя телефона, учитывая популярность переносимости номеров.
IP-адрес и другие методы, показанные выше, полезны для предложения значения по умолчанию, которое пользователь может настроить / исправить.
Я до сих пор не видел подробный ответ здесь, который получает часовой пояс. Вам не нужно геокодировать по IP-адресу или использовать PHP (смеется) или неправильно угадывать смещение.
Во-первых, часовой пояс - это не просто смещение от GMT. Это участок земли, в котором временные правила устанавливаются местными стандартами. В некоторых странах есть летнее время, и в разное время включается летнее время. Обычно важно получить фактическую зону, а не только текущее смещение.
Если вы намереваетесь сохранить этот часовой пояс, например, в пользовательских настройках вам нужна зона, а не только смещение. Для конвертации в реальном времени это не будет иметь большого значения.
Теперь, чтобы получить часовой пояс с JavaScript, вы можете использовать это:
>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.
Однако я обнаружил, что проще использовать этот надежный плагин, который возвращает форматированный часовой пояс Олсена:
С помощью PHP date
В функции вы получите дату и время сервера, на котором расположен сайт. Единственный способ получить пользовательское время - использовать 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();
?>
Но, с моей точки зрения, лучше спросить пользователей, является ли регистрация обязательной в вашем проекте.
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>';
Это всегда будет правильно показывать время в зависимости от часового пояса, который человек установил на своих компьютерных часах. Слава богу, не нужно никому ничего просить и сохранять это на местах.
Легко, просто используйте JavaScript getTimezoneOffset
функционировать так:
-new Date().getTimezoneOffset()/60;
Волшебство все, кажется, в
visitortime.getTimezoneOffset()
Это круто, я не знал об этом. Работает ли это в Internet Explorer и т. Д.? Оттуда вы сможете использовать JavaScript для Ajax, устанавливать куки, что угодно. Я бы, наверное, сам пошел по пути печенья.
Вы должны будете позволить пользователю изменить это все же. Мы пытались использовать геолокацию (через maxmind), чтобы сделать это некоторое время назад, и это было достаточно разумно неправильно - достаточно, чтобы этого не стоило делать, поэтому мы просто позволяем пользователю установить его в своем профиле и показываем уведомление пользователям, которые еще не установили их.
Любой знает о любых службах, которые будут сопоставлять IP с географическим местоположением
Что ж, к счастью для вас, этот ответ можно найти на нашем собственном веб-сайте stackru: как получить страну по определенному IP?
спойлер: http://www.hostip.info/use.html
Если вы используете OpenID для аутентификации, Simple Registration Extension решит проблему для аутентифицированных пользователей (вам нужно конвертировать из tz в число).
Другим вариантом будет вывод часового пояса из предпочтения страны агента пользователя. Это довольно грубый метод (не подходит для en-US), но он хорошо подходит.
Это просто с JavaScript и PHP:
Даже при том, что пользователь может связываться со своими внутренними часами и / или часовым поясом, лучший способ, который я нашел до сих пор, получить смещение, остается new Date().getTimezoneOffset();
, Он неинвазивен, не доставляет головной боли и устраняет необходимость полагаться на третьих лиц.
Скажи, у меня есть стол, users
, который содержит поле date_created int(13)
для хранения меток времени Unix;
Предполагая клиента creates a new account
, данные получены post
и мне нужно insert/update
date_created column
с меткой времени клиента Unix, а не с сервера.
Поскольку 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 и вход снова. Последний логин будет в будущем.
Я думаю... мы слишком много думаем.
Вот статья (с исходным кодом), которая объясняет, как определить и использовать локализованное время в приложении ASP.NET (VB.NET, C#):
Короче говоря, описанный подход опирается на JavaScript getTimezoneOffset
функция, которая возвращает значение, которое сохраняется в файле cookie сеанса и используется выделенным кодом для настройки значений времени между GMT и местным временем. Приятно то, что пользователю не нужно указывать часовой пояс (код делает это автоматически). В этом участвует больше (поэтому я и делаю ссылку на статью), но предоставленный код делает его действительно простым в использовании. Я подозреваю, что вы можете конвертировать логику в PHP и другие языки (если вы понимаете ASP.NET).
Вы можете сделать это на клиенте с моментом времени и отправить значение на сервер; пример использования:
> moment.tz.guess()
"America/Asuncion"
Получение правильного имени часового пояса базы данных TZ в PHP - это двухэтапный процесс:
С помощью JavaScript получите смещение часового пояса в минутах
getTimezoneOffset
, Это смещение будет положительным, если местный часовой пояс отстает от UTC, и отрицательным, если оно впереди. Таким образом, вы должны добавить противоположный знак к смещению.var timezone_offset_minutes = new Date().getTimezoneOffset(); timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
Передайте это смещение в PHP.
В 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. Он также содержит демо.
Попробуйте этот код 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'];
?>
Простой способ сделать это с помощью:
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
?>
Одним из возможных вариантов является использование Date
поле заголовка, которое определено в RFC 7231 и должно включать часовой пояс. Конечно, не гарантируется, что значение действительно является часовым поясом клиента, но это может быть удобной отправной точкой.
Существует несколько способов определить часовой пояс в браузере. Если есть стандартная функция, которая доступна и поддерживается вашим браузером, вам следует использовать ее. Ниже приведены три способа получения одной и той же информации в разных форматах. Избегайте использования нестандартных решений, которые делают какие-либо предположения на основе определенных предположений или жестко закодированных списков зон, хотя они могут быть полезны, если ничего другого сделать нельзя.
Получив эту информацию, вы можете передать ее как нестандартный заголовок запроса на сервер и использовать ее там. Если вам также нужно смещение часового пояса, вы также можете передать его на сервер в заголовках или в полезной нагрузке запроса, которую можно получить с помощью dateObj.getTimezoneOffset().
- Используйте Intl API для получения формата Olson (стандартный и рекомендуемый способ): обратите внимание, что это поддерживается не всеми браузерами. Перейдите по этой ссылке для получения подробной информации о поддержке браузера для этого. Этот API позволяет вам получить часовой пояс в формате Олсона, например, что-то вроде Азии/Калькутты, Америки/Нью-Йорка и т. д.
Нет такого способа определить часовой пояс в реальном HTML-коде или любом другом
user-agent
string, но вы можете сделать базовую функцию, получая ее с помощью JavaScript.
Я еще не знаю, как писать код на JavaScript, поэтому выполнение моей функции может занять время.
Однако вы можете попытаться получить фактический часовой пояс, также используя JavaScript с
getTzimezoneOffset()
функция в
Date
раздел или просто
new Date().getTimezoneOffset();
.
я думаю что
@Matt Johnson-Pints
на сегодняшний день является лучшим, и поиск CanIuse показывает, что теперь он получил широкое распространение:
https://caniuse.com/?search=Intl.DateTimeFormat().resolvedOptions().timeZone
Однако одна из проблем - понять, почему вы хотите знать часовой пояс. Потому что я думаю, что одна из вещей, которые упускают из виду большинство людей, - это то, что они могут измениться! Если пользователь путешествует со своим ноутбуком из Европы в Америку, если вы ранее сохранили его в базе данных, его часовой пояс теперь неверен (даже если пользователь на самом деле никогда не обновляет часовой пояс своих устройств). Это тоже проблема с
@Mads Kristiansen
ответ также, потому что пользователи путешествуют - вы не можете полагаться на это как данность.
Например, на моем ноутбуке с Linux отключен автоматический часовой пояс. Хотя время может обновлять мой часовой пояс, этого не происходит.
Итак, я считаю, что ответ - зачем вам это нужно? Клиентская сторона, безусловно, дает более простой способ выяснить это, но и клиентский, и серверный код будут зависеть от того, обновляет ли пользователь свой часовой пояс или он обновляется автоматически. Конечно, я могу ошибаться.