确定用户的时区

Kevin Dente 568 html browser timezone user-agent timezone-offset

Web服务器是否有标准方法可以确定用户在网页中的时区?

也许来自HTTP标头或user-agent字符串的一部分?

JD Isaacks.. 316

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

该方法getTimezoneOffset()将从GMT中减去您的时间并返回分钟数.所以如果你住在GMT-8,它将返回480.

把它分成几个小时,除以60.另外,注意标志与你需要的相反 - 它计算GMT与你的时区的偏差,而不是你的时区偏离GMT.要解决这个问题,只需乘以-1即可.

另请注意,w3school说:

由于使用夏令时的做法,返回的值不是常量.

  • 我不想与Keyo不同.getTimezoneOffset()的定义(根据ECMA标准http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5.26)是"以分钟为单位返回本地时间和UTC时间之间的差异" ". - 换句话说,它应该考虑夏令时.Mozilla的文档说"夏令时可以防止这个值在给定的语言环境中保持不变." (18认同)
  • 这并不总是适用于夏令时.获取时区偏移完全符合它的说法.它得到了抵消.时区ZONE实际上是一个地理区域.这不适用于夏令时,因为您不知道用户居住在哪个半球,或者他们的国家甚至是夏令时.为什么不使用它:`>>> date.toTimeString()"15:46:04 GMT + 1200(新西兰标准时间)" (16认同)
  • 这里有一点需要注意; 有些地方(例如加拿大的纽芬兰省)的时区偏离半小时,所以在除以60后你的答案可能不是整数. (8认同)
  • @xgretsch:它从GMT获得用户的*当前*偏移量.如果您在同一天出现另一个时间,那就没问题了(除非当前日期是转换日期,可能是错误的).但是,有许多时区与GMT具有相同的偏移量,并且它们可能具有不同的转换日期或不使用夏令时. (6认同)
  • 那些使用没有javascript支持的浏览器的手机用户呢?我喜欢这个问题,用户询问HTTP标头,用户代理......有没有办法使这个工作服务器端,尽可能准确? (5认同)
  • 这不考虑夏令时/夏令时,但Joseph Lust发布的链接确实如此:http://stackoverflow.com/a/5492192/462162 (5认同)

Ishmaeel.. 190

确定我所见过的时区的最流行(==标准?)方式只是询问用户自己.如果您的网站需要订阅,则可以将其保存在用户的个人资料数据中.对于匿名用户,日期可以显示为UTC或GMT或其他一些.

我不是想成为一个聪明的人.只是有时候某些问题在任何编程环境之外都有更好的解决方案.

  • @Ishmaeel:但是用户确实在国际旅行,他们每次从非本地时区登录时都不需要告诉他们的时区 (25认同)
  • 这不能回答这个问题,这显然意味着他正在寻找技术解决方案. (8认同)
  • @gWiz OP正在寻求标准解决方案.这是非常标准的. (5认同)
  • 当用户下载应该具有特定于其位置的开始时间的.ics文件时(例如全国各地的9-11am),该怎么办?他们不应该说他们的时区是什么样的. (4认同)
  • 最佳解决方案可能是询问用户(例如,在报告顶部提供时区下拉),同时在用户使用移动设备时将下拉选项默认为GPS确定的时区.提供位置信息的设备,否则默认为UTC. (4认同)

Mads Kristia.. 95

到目前为止,没有HTTP报头会报告客户端时区,尽管有人建议将其包含在HTTP规范中.

如果是我,我可能会尝试使用客户端JavaScript获取时区,然后使用Ajax或其他东西将其提交给服务器.

  • 奇怪的是,这是该问题的唯一**正确答案,它询问如何在服务器端进行.我怀疑有更多选票的其他答案的原因是因为一旦你意识到你需要做客户端你最终使用其他答案.但恕我直言,任何提出另一个答案的人都应该赞同这个. (10认同)

pix0r.. 54

JavaScript是获取客户端本地时间的最简单方法.我建议使用XMLHttpRequest发送回本地时间,如果失败,则回退到根据其IP地址检测到的时区.

就地理位置而言,我在几个项目中使用了MaxMind GeoIP并且运行良好,但我不确定它们是否提供时区数据.这是您支付的服务,它们每月为您的数据库提供更新.它们提供多种Web语言的包装器.


Adam.. 49

这是一个强大的JavaScript解决方案,用于确定浏览器所在的时区.

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

https://bitbucket.org/pellepim/jstimezonedetect

  • 不鼓励仅链接答案,因为如果链接消失,答案就不再有用了; 因为没有关注链接,读者不知道它是否给出了一个好的答案.在这种情况下,您可以澄清这是一个第三方库,它采用基于数据库的方法进行识别,并可能解释其操作的一些原则. (9认同)

Joseph Lust.. 39

这是一个更完整的方式.

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

从JS获取TZ和DST(通过返回机器)


Matt Johnson.. 31

首先,要了解JavaScript中的时区检测是不完美的.你可以得到本地时区偏移量为使用特定的日期和时间getTimezoneOffset上的一个实例Date对象,但是这并不完全一样全IANA时区一样America/Los_Angeles.

有一些选项可以工作:

  • 大多数现代浏览器在实施ECMAScript Internationalization API时都支持IANA时区,因此您可以这样做:

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

    结果是一个字符串,其中包含运行代码的计算机的IANA时区设置.

    Intl兼容性表中列出支持的环境.展开该DateTimeFormat部分,然后查看名为的功能resolvedOptions().timeZone defaults to the host environment.

    • 一些库,如Luxon使用此API通过函数来​​确定时区luxon.Settings.defaultZoneName.
  • 如果您需要支持更广泛的环境,例如旧的Web浏览器,您可以使用库来对时区进行有根据的猜测.它们通过首先尝试IntlAPI(如果可用)来工作,当它不可用时,它们会在几个不同的时间点询问对象的getTimezoneOffset功能Date,使用结果从内部数据集中选择适当的时区.

    无论jsTimezoneDetect时刻,时区具有此功能.

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

    在这两种情况下,结果只能被认为是猜测.在许多情况下,猜测可能是正确的,但不是全部.

    此外,必须定期更新这些库,以抵消许多较旧的JavaScript实现只知道当前时区的当前夏令时规则的事实. 关于这里的更多细节.

最终,更好的方法是实际询问用户他们的时区.提供可以更改的设置.您可以使用上述选项之一来选择默认设置,但不要使其与您的应用中的设置不同.

还有完全不同的方法,完全依赖于用户计算机的时区设置.相反,如果您可以收集纬度和经度坐标,则可以使用这些方法之一将其解析为时区.这适用于移动设备.


Westy92.. 30

使用Unkwntech的方法,我使用jQuery和PHP编写了一个函数.经过测试,确实有效!

在要将时区作为变量的PHP页面上,将此代码段放在页面顶部附近:

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

这将读取会话变量"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)或您所在的任何时区.


philfreo.. 24

使用jQuery在AJAX请求上将时区偏移量作为HTTP标头提交

$.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/


Keyo.. 22

我还没有在这里看到详细的答案,获得时区.您不需要通过IP地址进行地理编码或使用PHP(lol)或从偏移量错误猜测.

首先,时区不仅仅是GMT的偏移.这是一个按照当地标准设定时间规则的土地区域.有些国家/地区有夏令时,并且会在不同时间启用DST.获得实际区域通常很重要,而不仅仅是当前偏移.

如果您打算存储此时区,例如在用户首选项中,您需要区域而不仅仅是偏移量.对于实时转换,它无关紧要.

现在,要使用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


Sanjay Khatr.. 21

使用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();
?>

但根据我的观点,最好向用户询问您的项目是否必须注册.


用户甲.. 20

很容易,只需使用JavaScript getTimezoneOffset函数:

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

  • 这只是一个接受的答案的副本,为什么你甚至投票. (2认同)

用户甲.. 19

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

这将始终根据人在他/她的计算机时钟上设置的时区正确显示时间.感谢上帝,没有必要向任何人提出任何问题并将其保存到位.


Orion Edward.. 18

魔术似乎都在

visitortime.getTimezoneOffset()

那很酷,我不知道.它在Internet Explorer等中有效吗?从那里你应该能够使用JavaScript到Ajax,设置cookie,等等.我可能会自己去曲奇路线.

您需要允许用户更改它.我们尝试使用地理位置(通过maxmind)暂时执行此操作,并且经常出错 - 足以使其不值得这样做,因此我们只是让用户在其配置文件中设置它,并向用户显示通知还没有设定他们的.


用户甲.. 18

不要使用IP地址来确定位置(以及时区) - 这是因为使用NAT,代理(越来越受欢迎)和VPN,IP地址不一定真实地反映用户的实际位置,而是实现这些协议的服务器驻留

类似于美国区号对于定位电话用户不再有用,考虑到号码可携带性的普及.

上面显示的IP地址和其他技术对于建议用户可以调整/更正的默认值非常有用.


Dmitry Shech.. 14

如果您恰好使用OpenID进行身份验证,简单注册扩展将解决经过身份验证的用户的问题(您需要将tz转换为数字).

另一种选择是根据用户代理的国家/地区偏好推断时区.这是一种有点粗糙的方法(对en-US不起作用),但是很接近.


Alek Davis.. 14

这篇文章(包含源代码)解释了如何在ASP.NET(VB.NET,C#)应用程序中确定和使用本地化时间:

是时候了

简而言之,所描述的方法依赖于JavaScript getTimezoneOffset函数,该函数返回保存在会话cookie中的值,并由代码隐藏用于调整GMT和本地时间之间的时间值.好消息是用户不需要指定时区(代码会自动执行).还有更多内容(这就是我链接到文章的原因),但提供的代码使它非常易于使用.我怀疑你可以将逻辑转换为PHP和其他语言(只要你理解ASP.NET).


Naeem Ul Wah.. 12

一个简单的方法是使用:

new Date().getTimezoneOffset();

  • 为什么你从2年前转发了一个完全相同的答案(由John Isaacks提供):http://stackoverflow.com/a/1809974/836407? (6认同)

SummerBreeze.. 12

您可以使用moment-timezone在客户端上执行此操作并将值发送到服务器; 样品用量:

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

  • 函数名称告诉它的准确性;-) (4认同)

用户甲.. 11

使用JavaScript和PHP很简单:

即使用户可以弄乱他/她的内部时钟和/或时区,我到目前为止找到的最佳方法仍然是获得偏移量new Date().getTimezoneOffset();.它是非侵入性的,不会产生头痛,也不需要依赖第三方.

假设我有一个表,users包含一个字段date_created int(13),用于存储Unix时间戳;

假设一个客户端creates a new account,数据被接收post,而我需要insert/updatedate_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值插入到users表中以供将来参考,或者设置它作为会话或cookie.

PS但是,如果用户旅行和切换时区怎么办?以GMT + 4登录,快速前往GMT-1并再次登录.最后一次登录是将来的.

我想......我们想的太多了.


Dane Iracleo.. 9

这是我如何做到的.这会将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
?>


Berislav Lop.. 9

一种可能的选择是使用Date头字段,该字段在RFC 7231中定义并且应该包括时区.当然,不能保证该值实际上是客户的时区,但它可以是一个方便的起点.


用户甲.. 9

在PHP中获取有效的TZ数据库时区名称需要两个步骤:

  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中检测用户时区.它还包含一个演示.


用户甲.. 8

试试这个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'];
?>

  • 看起来http://api.easyjquery.com/已不再可用 (2认同)

提问时间:

查看次数:

165149 次

最近活跃:

3 月,3 周 前