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

可能来自 HTTP 标头或部分 user-agent 细绳?

没有正确的解决方案

其他提示

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

方法 getTimezoneOffset() 将从 GMT 中减去您的时间并返回分钟数。因此,如果您居住在 GMT-8,它将返回 480。

要将其换算为小时,请除以 60。另请注意,该符号与您需要的相反 - 它正在计算 GMT 与您的时区的偏移量,而不是您的时区与 GMT 的偏移量。要解决这个问题,只需乘以 -1 即可。

另请注意 w3学校 说:

由于使用日光节省时间的实践,返回的值不是一个恒定的。

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

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

到目前为止,还没有 HTTP 标头可以报告客户端时区,尽管建议将其包含在 HTTP 规范中。

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

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

至于地理位置,我用过 MaxMind GeoIP 在几个项目上,它运行良好,尽管我不确定它们是否提供时区数据。这是一项您付费的服务,他们每月为您的数据库提供更新。他们提供多种网络语言的包装器。

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

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

https://bitbucket.org/pellepim/jstimezonedetect

这里有一个更完整的方法。

  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 (通过回程机)

首先,请了解 JavaScript 中的时区检测并不完善。你可以找当地的 时区偏移量 对于特定的日期和时间使用 getTimezoneOffset 的一个实例 Date 对象,但这与完整的对象并不完全相同 IANA 时区 喜欢 America/Los_Angeles.

有一些选项可以工作:

  • 大多数现代浏览器在实施时都支持 IANA 时区 ECMAScript 国际化 API, ,所以你可以这样做:

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

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

    列出了支持的环境 在国际兼容性表中. 。展开 DateTimeFormat 部分,并查看名为的功能 resolvedOptions().timeZone defaults to the host environment.

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

    两个都 js时区检测时刻时区 有这个功能。

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

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

    此外,这些库必须定期更新,以抵消许多旧的 JavaScript 实现只知道 当前的 当地时区的夏令时规则。 更多详细信息请参见此处。

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

还有一种完全不同的方法 不是 完全依赖于用户计算机的时区设置。相反,如果您可以收集纬度和经度坐标,则可以使用以下命令将它们解析为时区 这些方法之一. 。这在移动设备上效果很好。

采用 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 到底是什么。嗯,简单来说就是这样:(创建一个名为 时区.php 并用上面的 URL 指向它)

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

如果工作正常,它将首先加载页面,执行 JavaScript,然后重新加载页面。然后,您将能够读取 $timezone 变量并随意使用它!它返回当前 UTC/GMT 时区偏移量 (GMT -7) 或您所在的任何时区。

我仍然没有在这里看到获取时区的详细答案。您不需要通过 IP 地址进行地理编码或使用 PHP(笑)或根据偏移量进行错误猜测。

首先,时区不仅仅是 GMT 的偏移量。这是一块按照当地标准制定时间规则的土地。一些国家实行夏令时,并会在不同时间开启夏令时。获取实际区域,而不仅仅是当前偏移量,通常很重要。

如果您打算存储该时区,例如在用户首选项中,您需要该时区而不仅仅是偏移量。对于实时转换来说,这并不重要。

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

将时区偏移量作为 AJAX 请求上的 HTTP 标头提交: jQuery

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

使用 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 getTimezoneOffset 函数如下:

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

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

这将始终根据用户在他/她的计算机时钟上设置的时区正确显示时间。无需向任何人询问任何事情并将其保存到位,谢天谢地!

神奇的一切似乎都在

visitortime.getTimezoneOffset()

太酷了,我不知道这一点。它可以在 Internet Explorer 等中使用吗?从那里您应该能够使用 JavaScript 进行 Ajax、设置 cookie 等等。我自己可能会走 cookie 路线。

不过,您需要允许用户更改它。不久前,我们尝试使用地理定位(通过 maxmind)来执行此操作,但它经常出错 - 足以使其不值得这样做,因此我们只是让用户在其个人资料中设置它,并向用户显示通知还没有设置他们的。

不要使用 IP 地址来明确确定位置(以及时区)——这是因为使用 NAT、代理(越来越流行)和 VPN,IP 地址不一定真实地反映用户的实际位置,而是反映用户所在的位置。驻留实现这些协议的服务器。

与美国区号不再用于定位电话用户类似,考虑到号码可移植性的普及。

IP 地址和上面显示的其他技术对于 建议默认 用户可以调整/纠正。

如果你碰巧正在使用 开放ID 用于身份验证, 简单注册扩展 将为经过身份验证的用户解决问题(您需要从 tz 转换为数字)。

另一种选择是根据用户代理的国家/地区首选项推断时区。这是一个有点粗糙的方法(不适用于 en-US),但可以得到很好的近似值。

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

是时候了

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

使用 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。

附:但是如果用户旅行并切换时区怎么办?在 GMT+4 登录,快速转到 GMT-1,然后再次登录。最后一次登录将在未来。

我认为...我们想太多了。

您可以在客户端上执行此操作 时刻时区 并将值发送到服务器;示例用法:

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

一个简单的方法是使用:

new Date().getTimezoneOffset();

在 PHP 中获取有效的 TZ 数据库时区名称分为两步:

  1. 使用 JavaScript,通过以下方式获取以分钟为单位的时区偏移量 getTimezoneOffset. 。如果本地时区晚于 UTC,则该偏移值为正;如果本地时区早于 UTC,则该偏移值为负。因此,您必须在偏移量上添加相反的符号。

    var timezone_offset_minutes = new Date().getTimezoneOffset();
    timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
    

    将此偏移量传递给 PHP。

  2. 在 PHP 中,将此偏移量转换为有效的时区名称 时区名称来自缩写 功能。

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

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

我是这样做的。这会将 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
?>

试试这个 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'];
?>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top