如何使用PHP自动检测时区或使用外部网站?

5

你好,我正在使用时间值来存储依赖于服务器时间的时间,但我的网站将被全球人士使用,因此我正在尝试自动检测用户的时区。谢谢。


浏览器的时区信息不是HTTP的一部分,因此您无法从标头中获取它。我认为您应该使用JavaScript,例如jsTimeZoneDetect库或PHP和JavaScript。 - Nuriddin Rashidov
4个回答

1
在大多数情况下,为了使您的网站正常运行,您不需要关心或知道用户的时区。通常,在服务器上使用UTC(Unix时间戳)存储所有内容,并将其作为此类传输到客户端。然后,使用JavaScript,您可以让用户的客户端UA在本地处理时区转换。
因此,在PHP中可以像这样实现。
<?php
$date = new DateTime("2016-09-18 4:45 AM", new DateTimezone("America/New_York"));
$timeStamp = $date->getTimeStamp();
?>
<script>
    var timeStamp = <?=json_encode($timeStamp * 1000)?>;
    alert(new Date(timeStamp);
</script>

用户在浏览器中看到适当格式的日期,根据他们的时区显示,而服务器不知道或不关心时区,因为它使用时区无关的时间戳进行传输。
然而,如果您希望可靠地获取用户的时区以进行除传输外的任何其他原因(即您需要在服务器端应用转换),那么最好只是询问用户。所有 HTML5 capable browsers now have an Geolocation API 都支持从客户端UA收集准确的地理位置信息(这也适用于移动设备,因为您不能依赖于移动设备的地理位置IP信息)。还有一些JavaScript库,如timezone-js,可以根据时区数据库准确地获取时区,PHP也依赖于此。
重要的一点是,当执行此操作时需要记住仅有GMT偏移量不足以确定时区,特别是在PHP中。因为PHP依赖于Olson时区数据库标识符,该标识符提供的不仅仅是GMT偏移量。例如,在加拿大多伦多和美国纽约,当前的GMT偏移量均为-0400。然而,在夏令时期间,两个时区的GMT偏移量都将变为-0500

还有更奇怪的情况,比如菲尼克斯和丹佛,这是亚利桑那州的两个城市,其中一个观察夏令时,另一个则不观察。因此,取决于一年中的哪个时候,它们可能处于相同的GMT偏移量,也可能不是。

$denver = new DateTime("now", new DateTimezone("America/Denver"));
$phoenix = new DateTime("now", new DateTimezone("America/Phoenix"));

var_dump($denver->format('c') , $phoenix->format('c'));

$denver->add(new DateInterval("P4M"));
$phoenix->add(new DateInterval("P4M"));
var_dump($denver->format('c'), $phoenix->format('c'));

上述代码的输出结果如下:

string(25) "2016-09-18T03:12:15-06:00"
string(25) "2016-09-18T02:12:15-07:00"
string(25) "2017-01-18T03:12:15-07:00"
string(25) "2017-01-18T02:12:15-07:00"

因此,除非您想陷入存储GMT偏移并在不同时间错误应用该偏移而丢失有价值的时区信息的陷阱中,最好存储Olson tz标识符,PHP可以使用它来准确地应用时区转换而不会丢失信息。 timezone-js库可以帮助您实现这一点,因为它依赖于与PHP相同的tz db的时区标识符。


0

0

您可以使用IP地理定位技术从IP地址获取访问者的位置,然后获取时区值。虽然IP地理定位在位置查询方面可能不是100%准确,但这应该是您可以获得的最佳非侵入式解决方案。

如果您对此方法感兴趣,可以在http://lite.ip2location.com下载免费的IP到时区数据库。


0

你可以使用JavaScript来实现:

常用的JavaScript代码来检测访问者的时区是:

var myDate = new Date();
document.write(myDate.getTimezoneOffset());

基本上有两件事情需要弄清楚访问者的时区。首先,我们需要确定与格林威治标准时间(GMT)的时间偏移量。这可以通过创建两个日期(一个本地日期和一个GMT日期)并比较它们之间的时间差来轻松完成:

var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);

你需要知道的第二件事是该位置是否遵守夏令时(DST)。由于夏令时总是在夏季观察,我们可以比较一月份两个日期之间的时间偏移量和六月份两个日期之间的时间偏移量。如果这些偏移量不同,那么我们就知道该位置遵守夏令时。如果这些偏移量相同,那么我们就知道该位置不遵守夏令时。
var june1 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0);
temp = june1.toGMTString();
var june2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);
var dst;
if (std_time_offset == daylight_time_offset) {
    dst = "0"; // daylight savings time is NOT observed
} else {
    dst = "1"; // daylight savings time is observed
}

为什么要给我点踩?我刚刚实现了这个功能,而且它运行得非常完美。 - Bhavin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接