2008-08-01 39 views
519

Web服务器是否有任何标准方式能够确定用户在网页中的时区?也许从HTTP头或用户代理字符串的一部分?确定用户的时区

+21

你可能会考虑让John Isaacks的答案是正确的......他的解决方法简单得多,说得轻松一些。 – catphive 2011-04-08 20:49:49

回答

73

虽然有人建议将HTTP头包含在HTTP规范中,但目前还没有HTTP头会报告客户端时区。

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

46

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

就地理定位而言,我在几个项目上使用了MaxMind GeoIP,它运行良好,但我不确定它们是否提供时区数据。这是您支付的服务,它们每月提供数据库更新。他们提供几种网页语言的包装。

+0

我已经投了这个答案,因为经纬度从像GeoIP这样的数据库中获得(它现在有一个免费版本)可以与将这种坐标转换为时区的数据库结合使用。我认为GeoNames有一个后者这样的数据库。 – 2011-11-20 06:52:34

+0

另请参阅[这个问题](http://stackoverflow.com/questions/5584602)。 – 2011-12-01 07:11:39

173

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

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

+3

当用户下载一个.ics文件时,应该有一个特定于他们的位置的开始时间(例如,在全国各地的上午9点11分)?他们不应该说他们的时区是imo。 – 2011-01-27 21:57:48

+0

为什么不接受这是正确的答案? Unkwntech给出的答案甚至不适用于非IE浏览器。 – 2011-02-18 01:33:02

+19

@Ishmaeel:但用户确实需要国际旅行,而且每次他们从某个非本地时区登录时都不需要告诉他们的时区 – 2011-07-22 08:04:51

14

魔都似乎是在

visitortime.getTimezoneOffset() 

这很酷,我不知道。它在IE等工作? 从那里你应该可以使用JS来ajax,设置cookie,不管。我可能会自己去饼干路线。

您需要允许用户修改它。我们之前尝试过使用地理位置(通过maxmind)来做这件事,而且这种错误经常是错的 - 足以让它不值得做,所以我们只是让用户在他们的个人资料中设置它,并向用户显示通知还没有设置他们的。

11

如果您碰巧使用OpenID进行身份验证,则Simple Registration Extension会sol对于经过身份验证的用户有问题(您需要将tz从数字转换为数字)。

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

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

getTimezoneOffset()将从GMT中减去您的时间并返回分钟数。所以如果你住在格林威治标准时间8,它将返回480。把这个数字除以60即可。另外,注意这个符号与你所需要的符号相反 - 它计算的是GMT时间的偏移量,而不是你的时区与GMT的偏移量。要解决这个问题,只需乘以-1。

编辑

还要注意的是w3school说:

返回的值不是一个常量,因为使用 夏令时的做法。

+1

这对我来说最有意义。有没有什么理由不应该使用这个问题,或者是否每个人都会让问题比他们需要的更困难。 – jordanstephens 2010-06-28 19:54:50

+0

@jordanstephens我不是专家,所以我不知道是否有情况下这不会工作,但它对我来说工作得很好。 – 2010-06-28 20:00:24

+5

那些使用带有浏览器而没有javascript支持的手机的用户呢? 我喜欢这个问题,用户询问HTTP标头,用户代理...有没有办法让这个工作服务器端,尽可能准确? – Nischal 2011-09-09 14:57:20

10

下面是一个物品(与源代码),说明如何确定和使用本地化时间在ASP.NET(VB.NET,C#)应用:

It's About Time

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

16

和PHP日期函数,你就可以了解哪些网站所在服务器的日期时间。获得用户时间的唯一方法是使用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(); 
?> 

但是按照我的观点,最好是向用户问一下,如果你的项目中注册是强制性的。

33

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

  1. 获得时区的用户
  2. 测试上DLS边界几天的时间来确定他们是否在使用DLS区域 偏移。

除了如下面:

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

Getting TZ and DST from JS(通过归路机)

+0

这对我有效!阅读博客帖子下的评论,对代码进行一些更新。 – arlomedia 2012-04-15 19:35:14

26

使用Unkwntech的做法,我写了使用jQuery和PHP函数。这已经过测试,并且确实有效!

在PHP页面,你想拥有的时区作为一个变量,有此代码段靠近页面顶部的地方:

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

这将读取会话变量“时间”,我们现在即将创建。

在同一页上,在,你需要首先包括jQuery的:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script> 

另外在,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://domain.com/timezone.php", 
       data: 'time='+ visitortimezone, 
       success: function(){ 
        location.reload(); 
       } 
      }); 
     } 
    }); 
</script> 

您可能会或可能没有注意到,但你需要将网址更改为你的实际域名。

最后一件事。你可能想知道timezone.php是什么。嗯,这很简单: (创建一个名为timezone.php并指向它与上面的网址一个新的文件)

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

如果这个工作正常,它会首先加载页面,执行JavaScript并重新加载页面。然后您将能够读取$ timezone变量并将其用于您的乐趣!它返回当前的UTC/GMT时区偏移量(北京时间)或任何时区你是在

+0

我这样做,但我可能有东西,检查当前$ _SESSION ['时间'],只有得到的JavaScript重新加载,如果它不同 – 2011-09-15 04:59:39

15

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

这将始终正确显示了基于该人已在他的计算机时钟设置时区的时间,不用问什么对任何人,并将其保存到感谢上帝的地方!

11

一个简单的方法来做到这一点是通过使用:

new Date().getTimezoneOffset(); 
+5

你为什么从2年前转贴相同的答案(由约翰伊萨克斯):http://stackoverflow.com/a/1809974/836407? – chown 2012-01-30 01:01:22

7

这里是我如何做到这一点。这会将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 
?> 
16

简单,只需使用JavaScript getTimezoneOffset功能,像这样:

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

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

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

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

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

现在,让你可以使用这个JavaScript时区:

>> new Date().toTimeString(); 
"15:46:04 GMT+1200 (New Zealand Standard Time)" 
//Use some regular expression to extract the time. 

但是我发现它很容易直接使用这个强大的插件,它返回奥尔森格式化时区:

https://github.com/scottwater/jquery.detect_timezone

14

获得实际的时区名称,请勿使用IP地址来明确地确定位置(和hense时区)的东西 - 这是因为使用NAT,代理服务器(越来越多流行)以及VPN,IP地址不一定真实地反映用户的实际位置,而是实现这些协议的服务器驻留的位置。

鉴于Number Portability的流行性,与区号查找电话用户不再有用的方法类似。

上面显示的IP和其他技术对于有用,建议用户可以调整/更正的默认

16

首先,了解JavaScript中的时区检测不完善。您可以在Date对象的实例上使用getTimezoneOffset获取本地时区偏移量对于特定日期和时间,但这与IANA time zone(如America/Los_Angeles)的实例不完全相同。

有一些可以工作,虽然选择:

  • 大多数现代浏览器都支持IANA时区在其执行ECMAScript Internationalization API的,所以你可以这样做:

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

    结果包含运行代码的计算机的IANA时区设置的字符串。

    支持环境列表in the Intl compatibility table。展开DateTimeFormat部分,并查看名为resolvedOptions().timeZone defaults to the host environment的功能。

  • 如果您需要支持更广泛的环境(例如较早的Web浏览器),则可以使用库在时区对进行猜测。他们首先尝试使用Intl API(如果可用),并且在不可用时,它们会在几个不同的时间点询问对象的getTimezoneOffset函数,并使用结果从内部数据集中选择适当的时区。

    jsTimezoneDetectmoment-timezone都具有此功能。

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

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

    此外,这些库必须定期更新,以抵消以下事实:许多较旧的JavaScript实现仅知道其当地时区的夏令时规则当前More details on that here.

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

还有完全不同的方法而不是完全依赖于用户计算机的时区设置。相反,如果您可以收集经度和纬度坐标,则可以使用one of these methods将这些坐标解析为时区。这在移动设备上运行良好。

6

一种可能的选择是使用Date标题字段,该字段在RFC 7231中定义,并且应该包含时区。当然,这并不能保证价值真的是客户的时区,但它可以是一个方便的起点。

8

简单与JSPHP

即使得到了弥补与他的内部时钟和/或时区,我发现迄今最好的方式,用户可以胡来,仍然new Date().getTimezoneOffset();。它的无创性,不会给头痛,并消除依赖第三方的需要。

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

假设一个客户端creates a new account,数据由post接受,我需要与客户的UNIX时间戳,而不是服务器对insert/updatedate_created column

由于在插入/更新时需要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 db 
$created = date("F j, Y, g:i a",$date_created);//return it to the user or whatever 

现在,这个例子可以适应人的需求,当谈到插入first时间戳...当它涉及到一个额外的时间戳或表格,你可能要考虑将tzo值插入用户表中以供将来参考,或将其设置为会话或cookie。

P.S.但是如果用户旅行并切换时区将会怎样。以GMT + 4登录,快速到达GMT-1并重新登录。最后登录将在未来。

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

5

你可以用moment-timezone做它在客户端和发送值的服务器;示例用法:

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

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

我写上一篇博客文章:http://usefulangle.com/post/31/detect-user-browser-timezone-name-in-php 它包含了演示也。

相关问题