我需要根据用户的 IP 或 http 标头了解用户当前所在的时区。
我得到了很多关于这个问题的答案,但我无法理解这些答案。有人说使用
-new Date().getTimezoneOffset()/60
(来自这里)。但这意味着什么呢?
我的 (index.php) 页面的根目录中有一个
date_default_timezone_set("Asia/Calcutta");
。因此,为此我必须动态获取时区并将其设置为 Asia/Calcutta
。
用代码总结 Matt Johnson 的答案:
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js">
</script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
var tz = jstz.determine(); // Determines the time zone of the browser client
var timezone = tz.name(); //For e.g.:"Asia/Kolkata" for the Indian Time.
$.post("url-to-function-that-handles-time-zone", {tz: timezone}, function(data) {
//Preocess the timezone in the controller function and get
//the confirmation value here. On success, refresh the page.
});
});
</script>
浏览器的时区信息不是 HTTP 规范的一部分,因此您不能仅从标头中获取它。
如果您有位置坐标(例如,通过移动设备 GPS),那么您可以使用以下方法之一查找时区。 然而,通过 IP 地址进行地理定位并不是一个很好的解决方案,因为 IP 通常是 ISP 或代理服务器的 IP,而这些 IP 可能位于另一个时区。
您可以使用一些策略来尝试检测时区,例如使用 jsTimeZoneDetect 库,这是一个很好的起点,但不够完善,您不能仅仅依赖它。 如果您使用的是 moment.js,那么 moment-timezone 中有一个名为
moment.tz.guess()
更新:在现代浏览器中,您可以使用
Intl.DateTimeFormat().resolvedOptions().timeZone
获取完整时区 ID,这在最初编写此答案时不可用。
使用 JavaScript 的
getTimezoneOffset()
函数的想法是有缺陷的,因为你没有获得时区 - 只是特定日期的单个偏移量。 请参阅 TimeZone 标签 wiki 标题为“TimeZone != Offset”的部分。
无论你怎么看,最终你都必须决定以下两种方法之一:
或
我在这个答案中更详细地讨论了这个问题(从 C# 的角度)。
依赖关系:
http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
//Get remote IP
$ip = $_SERVER['REMOTE_ADDR'];
//Open GeoIP database and query our IP
$gi = geoip_open("GeoLiteCity.dat", GEOIP_STANDARD);
$record = geoip_record_by_addr($gi, $ip);
//If we for some reason didnt find data about the IP, default to a preset location.
if(!isset($record)) {
$record = new geoiprecord();
$record->latitude = 59.2;
$record->longitude = 17.8167;
$record->country_code = 'SE';
$record->region = 26;
}
//Calculate the timezone and local time
try {
//Create timezone
$user_timezone = new DateTimeZone(get_time_zone($record->country_code, ($record->region!='') ? $record->region : 0));
//Create local time
$user_localtime = new DateTime("now", $user_timezone);
$user_timezone_offset = $user_localtime->getOffset();
}
//Timezone and/or local time detection failed
catch(Exception $e) {
$user_timezone_offset = 7200;
$user_localtime = new DateTime("now");
}
echo 'User local time: ' . $user_localtime->format('H:i:s') . '<br/>';
echo 'Timezone GMT offset: ' . $user_timezone_offset . '<br/>';
引用:S通过 IP 使用 MaxMind GeoIP 和 PHP 获取访客当地时间、日出和日落时间,作者:Stanislav Khromov
一个解决方案是询问他们!特别是在您可以捕获/注册用户的会员系统上 - 给他们一个选择。简单但准确。
这很好用...
echo <<<EOE
<script type="text/javascript">
if (navigator.cookieEnabled)
document.cookie = "tzo="+ (- new Date().getTimezoneOffset());
</script>
EOE;
if (!isset($_COOKIE['tzo'])) {
echo <<<EOE
<script type="text/javascript">
if (navigator.cookieEnabled) document.reload();
else alert("Cookies must be enabled!");
</script>
EOE;
die();
}
$ts = new DateTime('now', new DateTimeZone('GMT'));
$ts->add(DateInterval::createFromDateString($_COOKIE['tzo'].' minutes'));
时区在 HTTP 标头中不可用,但国家/地区(缩写)位于 ACCEPT_LANGUAGE 标头中。它类似于“en-US”(美国是国家/地区代码)。这可以与 JavaScript 信息结合起来,以更好地了解用户的时区。
这就是我在 JS 中使用的:
function timezone() {
var now = new Date();
var jano = new Date(now.getFullYear(), 0, 1).getTimezoneOffset()/-60;
var julo = new Date(now.getFullYear(), 6, 1).getTimezoneOffset()/-60;
var tz = Math.min(jano, julo);
if (jano != julo) tz += ((jano < julo) ? 'S' : 'W') + Math.abs(jano - julo);
return tz;
}
这会为中心区域返回一个类似“-6S1”的字符串(标准时间偏移为-6小时,DST在夏季有效并增加1小时)。我使用 cookie 使其可供 PHP 使用。 PHP 在 TZ 数据库中搜索与此匹配的区域以及国家/地区。对于这里(美国,-6S1)有 7 个匹配区域,第一个是“美国/芝加哥”。
顺便说一句,数据库中有 2 个区域的 DST 增加了 1 小时以外的时间:豪勋爵岛 (10.5W0.5) 和南极洲巨魔站 (0W2)。