如何检测用户的时区?

问题描述 投票:0回答:6

我需要根据用户的 IP 或 http 标头了解用户当前所在的时区。

我得到了很多关于这个问题的答案,但我无法理解这些答案。有人说使用

-new Date().getTimezoneOffset()/60
来自这里)。但这意味着什么呢?

我的 (index.php) 页面的根目录中有一个

date_default_timezone_set("Asia/Calcutta");
。因此,为此我必须动态获取时区并将其设置为
Asia/Calcutta

javascript php timezone
6个回答
44
投票

用代码总结 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>

26
投票

浏览器的时区信息不是 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”的部分。

无论你怎么看,最终你都必须决定以下两种方法之一:

  • 仅以 UTC 格式向浏览器发送时间,并在浏览器上使用 JavaScript 转换为用户可能将其计算机设置为的任何本地时区。

我在这个答案中更详细地讨论了这个问题(从 C# 的角度)。


3
投票

依赖关系:

  1. http://www.maxmind.com/download/geoip/api/php/php-latest.tar.gz
  2. 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


1
投票

一个解决方案是询问他们!特别是在您可以捕获/注册用户的会员系统上 - 给他们一个选择。简单但准确。


0
投票

这很好用...

  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'));

0
投票

时区在 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)。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.