php 如何检测用户的时区?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16525617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 11:18:20  来源:igfitidea点击:

How to detect user's timezone?

javascriptphptimezone

提问by Dan

I need to know what time zone is currently my users are in based on their IP or http header.

我需要根据他们的 IP 或 http 标头知道我的用户当前所在的时区。

I got many answer regarding this issue, but i could not understood those answer. Some said use -new Date().getTimezoneOffset()/60(from here). But what does it mean?

我得到了很多关于这个问题的答案,但我无法理解这些答案。有人说使用-new Date().getTimezoneOffset()/60从这里)。但是这是什么意思?

I have a date_default_timezone_set("Asia/Calcutta");in the root of my (index.php) page. So for this I have to get the timezone dynamically and set it in place of Asia/Calcutta.

date_default_timezone_set("Asia/Calcutta");我的(index.php)页面的根目录中有一个。因此,为此我必须动态获取时区并将其设置为Asia/Calcutta.

回答by Elavarasan M Lee

To summarize Matt Johnson's answer in terms of code:

总结马特约翰逊在代码方面的回答:

<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>

回答by Matt Johnson-Pint

Time zone information of the browser is not part of the HTTP spec, so you can't just get it from a header.

浏览器的时区信息不是 HTTP 规范的一部分,因此您不能仅从标头中获取它。

If you have location coordinates (from a mobile device GPS, for example), then you can find the time zone using one of these methods. However, geolocation by IP address is not a great solution because often the IP is that of an ISP or proxy server which may be in another time zone.

如果您有位置坐标(例如来自移动设备 GPS),那么您可以使用以下方法之一找到时区。然而,通过 IP 地址进行地理定位并不是一个很好的解决方案,因为 IP 通常是 ISP 或代理服务器的 IP,它们可能位于另一个时区。

There are some strategies you can use to try to detect the time zone, such as using jsTimeZoneDetectlibrary, which is a great starting point, but imperfect enough that you can't just rely on that alone. If you're using moment.js, there's a built in function in moment-timezone called moment.tz.guess()that does the same thing.

您可以使用一些策略来尝试检测时区,例如使用jsTimeZoneDetect库,这是一个很好的起点,但不够完善,您不能仅依靠它。如果您使用的是 moment.js,则在 moment-timezone 中有一个内置函数moment.tz.guess()可以执行相同的操作。

The idea of using JavaScript's getTimezoneOffset()function is flawed in that you are not getting a time zone - just a single offset for a particular date. See the TimeZone tag wiki's section titled "TimeZone != Offset".

使用 JavaScriptgetTimezoneOffset()函数的想法有缺陷,因为您没有获得时区 - 只是特定日期的单个偏移量。请参阅TimeZone 标签 wiki的标题为“TimeZone != Offset”的部分。

However you look at it, ultimately you have to decide on one of two approaches:

不管你怎么看,最终你必须决定两种方法之一:

OR

或者

  • Only send time to the browser in UTC, and use JavaScript on the browser to convert to whatever local time zone the user might have their computer set to.
  • 仅以 UTC 格式向浏览器发送时间,并在浏览器上使用 JavaScript 转换为用户可能将其计算机设置为的任何本地时区。

I discuss this in more detail (from a c# perspective) in this answer.

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

回答by davidcondrey

Dependencies:

依赖项:

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

citation: SGet visitor local time, sunrise and sunset time by IP with MaxMind GeoIP and PHP by Stanislav Khromov

引文:SGet 访问者本地时间、日出和日落时间通过 IP 与 MaxMind GeoIP 和 PHP 由 Stanislav Khromov

回答by Antony

One solution is to ask them! Especially on members systems where you can capture/register a user - give them a choice at that point. Simple but accurate.

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

回答by Mark Lloyd

Timezone is not available in the HTTP header, but country (abbreviation) is in the ACCEPT_LANGUAGE header. It'll be something like "en-US" (US is the country code). This can be combined with the JavaScript information to get a good idea of the user's timezone.

时区在 HTTP 标头中不可用,但国家(缩写)在 ACCEPT_LANGUAGE 标头中。它将类似于“en-US”(US 是国家/地区代码)。这可以与 JavaScript 信息相结合,以很好地了解用户的时区。

This is what I'm using in JS:

这是我在 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;
}

This returns a string like "-6S1" for the central zone (standard time offset of -6 hours, DST active in the summer and adds 1 hour). I use a cookie to make this available to PHP. PHP searches the TZ database for zones that match this, and the country. For here (US, -6S1) there are 7 matching zones, the first is "America/Chicago".

这将为中央区域返回一个类似“-6S1”的字符串(标准时间偏移为 -6 小时,夏令时在夏季活动并增加 1 小时)。我使用 cookie 使其可用于 PHP。PHP 在 TZ 数据库中搜索与此匹配的区域和国家/地区。对于这里 (US, -6S1) 有 7 个匹配区域,第一个是“America/Chicago”。

BTW, there are 2 zones in the database where DST adds something other than 1 hour: Lord Howe Island (10.5W0.5) and Troll Station, Antarctica (0W2).

顺便说一句,数据库中有 2 个区域,其中 DST 添加了 1 小时以外的时间:豪勋爵岛 (10.5W0.5) 和南极洲的巨魔站 (0W2)。

回答by Lauber Bernhard

This works fine...

这工作正常...

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