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

可能来自HTTP报头或用户代理字符串的一部分?


当前回答

一个可能的选项是使用Date报头字段,该字段在RFC 7231中定义,应该包括时区。当然,不能保证该值真的是客户机的时区,但它可以作为一个方便的起点。

其他回答

有几种方法可以在浏览器中确定时区。如果您的浏览器提供并支持一个标准函数,那么您就应该使用它。下面是用不同格式获取相同信息的三种方法。避免使用基于特定假设或硬编码区域列表进行猜测的非标准解决方案,尽管如果没有其他办法,它们可能会有所帮助。

一旦你有了这个信息,你可以把它作为一个非标准的请求头传递给服务器,并在那里使用它。如果你还需要时区偏移量,你也可以在头文件中或请求有效载荷中传递给服务器,可以使用dateObj.getTimezoneOffset()来检索。

使用Intl API获取Olson格式(标准和推荐的方式):注意,这不是所有浏览器都支持。有关浏览器对此的支持的详细信息,请参阅此链接。 这个API可以让你获得Olson格式的时区,例如亚洲/加尔各答,美国/纽约等。

Intl . DateTimeFormat () timeZone resolvedOptions()。

使用Date对象获得较长的格式,如印度标准时间,东部标准时间等:这是所有浏览器支持的。

let dateObj =新的日期(2021,11,25,09,30,00); / /然后 dateObj.toString () / /收益率 2021年12月25日星期六09:30:00 GMT+0530(印度标准时间)//我位于印度(IST)

注意,字符串包含长格式和短格式的时区信息。你现在可以使用regex来获取这些信息:

let longZoneRegex = /\((.+)\)/; dateObj.toString () .match (longZoneRegex); / /收益率 ['(印度标准时间)','印度标准时间',索引:34,输入:' 2021年12月25日星期六09:30:00 GMT+0530(印度标准时间)',组:未定义] //注意output是一个数组,所以使用output[1]来获取时区名称。

使用Date对象获取短格式,如GMT+0530, GMT-0500等:所有浏览器都支持。

类似地,你也可以得到短格式:

let shortZoneRegex = /GMT[+-]\d{1,4}; dateObj.toString () .match (shortZoneRegex); / /收益率 ['GMT+0530',索引:25,输入:' 2021年12月25日星期六09:30:00 GMT+0530(印度标准时间)',分组:未定义] //注意output是一个数组,所以使用output[0]来获取时区名称。

所有的魔力似乎都在

visitortime.getTimezoneOffset()

真酷,我还不知道呢。它能在ie浏览器上运行吗?从这里你应该能够使用JavaScript到Ajax,设置cookie等等。我自己可能也会吃饼干。

不过,您需要允许用户更改它。我们曾尝试使用地理定位(通过maxmind)来实现这一点,但这是错误的,不值得这么做。所以我们让用户在他们的配置文件中设置它,并向还没有设置的用户显示一个通知。

它是简单的JavaScript和PHP:

即使用户可以打乱他/她的内部时钟和/或时区,我迄今为止发现的最好的方法,以获得偏移量,仍然是新的Date(). gettimezoneoffset();。它是非侵入性的,不会让人头痛,也不需要依赖第三方。

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

假设客户端创建了一个新帐户,数据是通过post接收的,我需要用客户端的Unix时间戳插入/更新date_created列,而不是服务器的。

由于在插入/更新时需要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

现在,这个示例可能适合您的需要,当涉及插入第一个时间戳时……当涉及到额外的时间戳或表时,您可能需要考虑将tzo值插入到用户表中以供将来参考,或者将其设置为会话或cookie。

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

我认为……我们想得太多了。

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

至于地理定位,我已经在几个项目中使用了MaxMind GeoIP,它工作得很好,尽管我不确定他们是否提供时区数据。这是一项你付费的服务,他们每月更新你的数据库。他们提供多种网络语言的包装器。

我认为@Matt Johnson-Pints是目前为止最好的,CanIuse搜索显示它现在被广泛采用:

.timeZone .resolvedOptions https://caniuse.com/?search=Intl.DateTimeFormat () ()

其中一个挑战是考虑为什么要知道时区。因为我认为大多数人忽略了一件事,那就是他们是可以改变的!如果一个用户带着他的笔记本电脑从欧洲旅行到美国,如果你之前把它存储在数据库中,那么他们的时区现在是不正确的(即使用户从来没有更新过他们的设备时区)。这也是@Mads Kristiansen回答的问题,因为用户会旅行——你不能把它当作给定的。

例如,我的Linux笔记本电脑关闭了“自动时区”。虽然时间可能会更新我的时区却不会。

所以我相信答案是——你需要它做什么?客户端似乎提供了一种更简单的方法来确定它,但是客户端和服务器端代码都将依赖于用户更新他们的时区或自动更新。我当然可能是错的。