Web服务器是否有标准方法可以确定用户在网页中的时区?
也许来自HTTP标头或user-agent
字符串的一部分?
-new Date().getTimezoneOffset()/60;
方法getTimezoneOffset()
将从GMT中减去你的时间并返回分钟数。所以如果你住在GMT-8,它将返回480。
把它分成几个小时,除以60.另外,注意标志与你需要的相反 - 它计算GMT与你的时区的偏差,而不是你的时区偏离GMT。要解决这个问题,只需乘以-1即可。
另请注意,w3school说:
由于使用夏令时的做法,返回的值不是常量。
我还没有在这里看到详细的答案,获得时区。您不需要通过IP地址进行地理编码或使用PHP(lol)或错误地从偏移量猜测。
首先,时区不仅仅是GMT的偏移。这是一个按照当地标准设定时间规则的土地区域。有些国家/地区有夏令时,并且会在不同时间启用DST。获得实际区域通常很重要,而不仅仅是当前偏移。
如果您打算存储此时区,例如在用户首选项中,您需要区域而不仅仅是偏移量。对于实时转换,它无关紧要。
现在,要使用javascript获取时区,您可以使用:
http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/
但是我发现简单地使用这个返回Olsen格式化时区的健壮插件更容易:
>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.
使用PHP https://github.com/scottwater/jquery.detect_timezone函数,您将获得站点所在服务器的日期时间。获取用户时间的唯一方法是使用JavaScript。
但我建议你,如果你的网站需要注册,那么最好的方法是在注册为必填字段时询问用户。您可以在注册页面中列出各种时区,并将其保存在数据库中。在此之后,如果用户登录到站点,则可以根据用户选择的时区设置该会话的默认时区。
您可以使用PHP函数date
设置任何特定时区。这将为用户设置指定的时区。
用户的时区基本上是客户端,因此我们必须使用JavaScript。
下面是使用PHP和JavaScript获取用户时区的脚本。
date_default_timezone_set
但根据我的观点,最好向用户询问您的项目是否必须注册。
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();
?>
只需将Unix时间戳格式的时间提供给此函数; JavaScript已经知道用户的时区。
像这样:
PHP:
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;
}
这将始终根据人在他/她的计算机时钟上设置的时区正确显示时间。感谢上帝,没有必要向任何人提出任何问题并将其保存到位。
很简单,只需使用JavaScript echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';
函数:
getTimezoneOffset
不要使用IP地址来确定位置(以及时区) - 这是因为使用NAT,代理(越来越受欢迎)和VPN,IP地址不一定真实地反映用户的实际位置,而是实现这些协议的服务器驻留
类似于美国区号对于定位电话用户不再有用,考虑到号码可携带性的普及。
上面显示的IP地址和其他技术对于建议用户可以调整/更正的默认值非常有用。
魔术似乎都在
-new Date().getTimezoneOffset()/60;
那很酷,我不知道。它在Internet Explorer等中有效吗?从那里你应该能够使用JavaScript到Ajax,设置cookie,等等。我可能会自己去cookie路线。
您需要允许用户更改它。我们尝试使用地理位置(通过maxmind)暂时执行此操作,并且经常出错 - 足以使其不值得这样做,因此我们只需让用户在其配置文件中设置它,并向用户显示通知还没有设定他们的。
如果您碰巧使用visitortime.getTimezoneOffset()
进行身份验证,OpenID将解决经过身份验证的用户的问题(您需要将tz转换为数字)。
另一种选择是根据用户代理的国家/地区偏好推断时区。这是一种有点粗糙的方法(对en-US不起作用),但是很接近。
这篇文章(包含源代码)解释了如何在ASP.NET(VB.NET,C#)应用程序中确定和使用本地化时间:
简而言之,所描述的方法依赖于JavaScript It's About Time函数,该函数返回保存在会话cookie中的值,并由代码隐藏用于调整GMT和本地时间之间的时间值。好消息是用户不需要指定时区(代码会自动执行)。还有更多内容(这就是我链接到文章的原因),但提供的代码使它非常易于使用。我怀疑你可以将逻辑转换为PHP和其他语言(只要你理解ASP.NET)。
使用JavaScript和PHP很简单:
即使用户可以弄乱他/她的内部时钟和/或时区,我到目前为止找到的最好方法是获得偏移,仍然是getTimezoneOffset
。它是非侵入性的,不会产生头痛,也不需要依赖第三方。
假设我有一个表,new Date().getTimezoneOffset();
,包含一个字段users
,用于存储Unix时间戳;
假设客户端date_created int(13)
,数据由creates a new account
接收,我需要post
insert/update
与客户端的Unix时间戳,而不是服务器的。
由于插入/更新时需要timezoneOffset,因此当客户端提交表单时,它会作为额外的$ _POST元素传递,因此无需将其存储在会话和/或cookie中,也不会有额外的服务器命中。
date_created column
假设服务器收到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时,您可以像这样转换时间戳:
date_created=$user_timestamp
现在,这个例子可能满足一个人的需求,当涉及到插入$date_created = // Get from the database
$created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever
时间戳时...当涉及到一个额外的时间戳或表时,您可能需要考虑将tzo值插入到users表中以供将来参考或设置它作为会话或cookie。
附:但是如果用户旅行并切换时区怎么办?以GMT + 4登录,快速前往GMT-1并再次登录。最后一次登录是将来的。
我想......我们想的太多了。
您可以使用first
在客户端上执行此操作并将值发送到服务器;样品用量:
moment-timezone
确定我所见过的时区的最流行(==标准?)方式只是询问用户自己。如果您的网站需要订阅,则可以将其保存在用户的个人资料数据中。对于匿名用户,日期可以显示为UTC或GMT或其他一些。
我不是想成为一个聪明的人。只是有时候某些问题在任何编程环境之外都有更好的解决方案。
在PHP中获取有效的TZ数据库时区名称分为两步:
> moment.tz.guess()
"America/Asuncion"
获得几分钟内的时区偏移。如果本地时区落后于UTC,则此偏移量为正,如果前置,则偏移量为负。因此,您必须在偏移处添加相反的符号。
getTimezoneOffset
将此偏移量传递给PHP。var timezone_offset_minutes = new Date().getTimezoneOffset();
timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
我写过一篇博文:// 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>
。它还包含一个演示。
一个简单的方法是使用:
How to Detect User Timezone in PHP
一种可能的选择是使用new Date().getTimezoneOffset();
头字段,该字段在Date
中定义并且应该包括时区。当然,不能保证该值实际上是客户的时区,但它可以是一个方便的起点。
这是我如何做到的。这会将PHP默认时区设置为用户的本地时区。只需将以下内容粘贴到所有页面的顶部即可:
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
?>
到目前为止,没有HTTP报头会报告客户端时区,尽管有人建议将其包含在HTTP规范中。
如果是我,我可能会尝试使用客户端JavaScript获取时区,然后使用Ajax或其他东西将其提交给服务器。
JavaScript是获取客户端本地时间的最简单方法。我建议使用XMLHttpRequest发回本地时间,如果失败,则回退到根据其IP地址检测到的时区。
就地理位置而言,我在几个项目中使用了MaxMind GeoIP并且运行良好,但我不确定它们是否提供时区数据。这是您支付的服务,它们每月为您的数据库提供更新。它们提供多种Web语言的包装器。
这是一个强大的JavaScript解决方案,用于确定浏览器所在的时区。
>>> var timezone = jstz.determine();
>>> timezone.name();
"Europe/London"
这是一个更完整的方式。
摘录如下:
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;
}
qazxsw poi(通过Wayback Machine)
首先,要了解JavaScript中的时区检测是不完美的。您可以在Getting TZ and DST from JS对象的实例上使用getTimezoneOffset
获取特定日期和时间的本地时区偏移量,但这与Date
这样的完整IANA time zone不完全相同。
有一些选项可以工作:
America/Los_Angeles
时都支持IANA时区,因此您可以这样做:
ECMAScript Internationalization API
结果是一个字符串,其中包含运行代码的计算机的IANA时区设置。
const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
列出了支持的环境。展开in the Intl compatibility table部分,查看名为DateTimeFormat
的功能。
某些库(例如resolvedOptions().timeZone defaults to the host environment
)使用此API通过Luxon等函数确定时区。luxon.Settings.defaultZoneName
API,如果它不可用,他们会在几个不同的时间点查询Intl
对象的getTimezoneOffset
函数,使用结果从内部数据集中选择合适的时区。
Date
和jsTimezoneDetect都有这个功能。
moment-timezone
在这两种情况下,结果只能被认为是猜测。在许多情况下,猜测可能是正确的,但不是全部。
此外,必须定期更新这些库,以抵消许多较旧的JavaScript实现只知道当前时区的当前夏令时规则的事实。 // using jsTimeZoneDetect
var tzid = jstz.determine().name();
// using moment-timezone
var tzid = moment.tz.guess();
最终,更好的方法是实际询问用户他们的时区。提供可以更改的设置。您可以使用上述选项之一来选择默认设置,但不要使其与您的应用中的设置不同。
还有完全不同的方法,完全不依赖于用户计算机的时区设置。相反,如果您可以收集纬度和经度坐标,则可以使用More details on that here.将其解析为时区。这适用于移动设备。
使用Unkwntech的方法,我使用jQuery和PHP编写了一个函数。经过测试,确实有效!
在要将时区作为变量的PHP页面上,将此代码段放在页面顶部附近:
one of these methods
这将读取会话变量“time”,我们现在要创建它。
在同一页面上,在<head>中,首先需要包含jQuery:
<?php
session_start();
$timezone = $_SESSION['time'];
?>
同样在<head>中,在jQuery下面,粘贴这个:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
您可能已经注意到或未注意到,但您需要将URL更改为您的实际域。
最后一件事。你可能想知道什么是timezone.php。嗯,就是这样:(创建一个名为timezone.php的新文件,并使用上面的URL指向它)
<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>
如果这样可以正常工作,它将首先加载页面,执行JavaScript并重新加载页面。然后,您将能够阅读$ timezone变量并将其用于您的乐趣!它返回当前的UTC / GMT时区偏移量(GMT -7)或您所在的任何时区。
使用<?php
session_start();
$_SESSION['time'] = $_GET['time'];
?>
在AJAX请求上将时区偏移量作为HTTP标头提交
jQuery
您还可以使用$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
}
});
中的moment.tz.guess();
执行类似的操作以获取实际时区名称