如何收集访问者的时区信息?

我两者都需要:

时区(例如,欧洲/伦敦) 与UTC或GMT的偏移(例如,UTC+01)


当前回答

JavaScript:

var d = new Date(); var n = d.getTimezoneOffset(); Var时区= n / -60; console.log(时区);

其他回答

你可以使用:

moment-timezone

<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>

// retrieve timezone by name (i.e. "America/Chicago")
moment.tz.guess();

浏览器时区检测是相当棘手的,因为浏览器提供的信息很少。

Moment Timezone在当年的一些时刻上使用Date.getTimezoneOffset()和Date.toString()来收集尽可能多的关于浏览器环境的信息。然后将该信息与加载的所有时区数据进行比较,并返回最接近的匹配。如果存在重叠,则返回人口最多的城市所在的时区。

console.log(moment.tz.guess()); // America/Chicago

这个问题已经有30多个答案了,但我敢肯定,有些人来到这里,却真的不知道他们在寻找什么。

惊喜!你要打开一个棘手的罐子了!

我强烈推荐你阅读我最近写的一篇关于在JS中处理时区的头痛的文章!https://medium.com/@EyeDin/time-and-time-zone-headaches-in-javascript-ae4d873a665d

你到底在找什么?

根据您的实际用例,您实际上需要不同的东西。


1)一种将固定时间点(比如2021年11月13日旧金山晚上11:35:21)转换为用户的挂钟时间的方法,用户可能在世界上任何地方。

使用.toLocaleString()。

通过DateTimeFormat中列出的locale和选项两个参数,它有更多用于格式化的自定义参数。它甚至支持不同的日历、语言、年、月、日等格式(没有传递的参数将使用用户的默认设置,这可能是最理想的)。

作为开发人员,只需将该时间点值(例如,Sales活动或竞赛的开始时间)作为UNIX时间戳数(即UTC从1/1/1970开始的秒数,与时区无关,与dst0无关)传递给客户机,然后执行new Date(timestamp). tolocalestring()。例如,对于上面的时间点,值是1636875321000(毫秒),via +dateWithTimeZone("America/Los_Angeles",2021,10,13,23,35,21)使用这个答案的函数。


2)能够在3个月后的当地时间上午9点向用户发送通知/电子邮件

这是一个完全不同的要求!非常非常不同!

格林尼治时间8点还不够吗?

No!

这只是用户在某个时间点所在的时区,比如“现在,今天”。

您如何知道用户是否使用日光节约时间?(美国的亚利桑那州没有,其他很多国家、州甚至县都没有!) 您如何知道用户是在DST中还是不在DST中?旧金山是冬天(GMT-8)还是阿拉斯加是夏天(同样是GMT-8) ?看看这个巨大的列表,你会抓狂的:https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

“PDT”还不够吗?

No!

首先,PDT并不是全年都有的。现在是11月,timeanddate.com网站上写着“PDT目前没有位置。你想看PST吗?”(阅读我上面的Medium文章了解更多细节。)

除非你想要从客户端到客户端的UI字符串,这个PDT/CEST/等等。一点价值都没有!

为什么?因为墨西哥的蒂华纳和美国的旧金山在6月都在PDT,但他们有不同的DST(日光节约)日,他们切换到PST。你需要知道这一点!

美国2022年夏令时为2022年3月13日至11月6日。墨西哥2022年的夏令时时间为2022年4月3日至2022年10月30日。因此,虽然蒂华纳和旧金山在近93%的时间里共享“PDT/PST”,但在7%的时间里(例如,2022年的3月14日至4月3日,以及10月31日至11月6日),它们并不匹配。

所以,即使你知道现在是11月,也知道用户处于PDT状态,你也无法判断用户设备中的时间戳数字是2022年4月1日上午9点。

PS.如果你试图从new Date(). tostring()中获取PDT,情况会更糟。仅供参考,如果你将你的机器的语言环境更改为es-MX(西班牙语,这是13%的美国人的语言),你会得到这样的结果:

> new Date().toString()
'Sun Nov 14 2021 00:47:25 GMT-0800 (hora estándar del Pacífico)'

祝hedP好运!

那么,我该怎么办呢?

唯一正确的方法是使用IANA(阅读“标准”)时区值。这是维基百科页面的第二栏。它来自:

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

它返回IANA值,即旧金山的America/Los_Angeles。如果有的话,这是您应该为用户存储在数据库中的值。您可以从时区获得关于它的各种信息。Json包,并将时间从/转换为该时区,加上日期(这很重要),就像这个答案。

那么IE11呢?

IE11不支持Intl....事情大多数填充物只是猜测,是不准确的。所以,试着放弃对IE11的支持,或者使用一个库,为一些不准确做好准备。


3)我只是想知道他们目前的时区偏移(例如-8:00)

你可能不应该这么做。我想不出你需要这个的真正原因。再说一次,知道今天的值,并不能告诉你明天的值是多少。

不管怎样,你总能得到这个值

new Date().getTimezoneOffset() / 60

在客户端。

注意:. gettimezoneoffset()不是date对象的时区偏移量,你是在调用它。请阅读文档。

准确地说,它接受传递的Date对象(该对象具有时间戳,引用历史中的单个时间点),然后告诉该时间点的UTC时间和本地时间之间的差值。

同样,这取决于日期。看到的:

console.log(new Date("6/13/2021").getTimezoneOffset() / 60); // It's 7 on a machine that runs in San Francisco
console.log(new Date("11/13/2021").getTimezoneOffset() / 60); // It's 8 on a machine that runs in in San Francisco

有图书馆吗?

下面是支持时区交换的库列表。

但是,请记住,您必须首先解决设计问题,然后再寻找代码。关于时区的事情很容易变得复杂,你必须知道“PDT”和“GMT-8”不是全年为用户存储在DB中的有信息/有价值的时区值。:)

这可能不是最优雅的解决方案,但却是最通用的。

这使用了Intl的timeZoneName属性。DateTimeFormat

function getTimeZone(zoneName = "long") { // set up formatter let formatter = new Intl.DateTimeFormat(undefined, { timeZoneName: zoneName }); // run formatter on current date return formatter.formatToParts(Date.now()) // extract the actual value from the formatter, only reliable way i can find to do this .find(formatted => formatted.type === "timeZoneName")['value']; } // console.log every type for (const zoneName of ['short', 'long', 'shortOffset', 'longOffset', 'shortGeneric', 'longGeneric']) { console.log(`${zoneName}: ${getTimeZone(zoneName)}`) } /* short: CDT long: Central Daylight Time shortOffset: GMT-5 longOffset: GMT-05:00 shortGeneric: CT longGeneric: Central Time */

这不仅得到格式化的GMT偏移时间(即GMT-5),还得到时区的口语化名称(即中央日光时间)。

这个方法唯一不做的是获取IANA时区。我推荐上面的答案。

据我所知,DateTimeFormat没有自定义格式化的方法,因此使用formattpart,这似乎是获得时区的唯一可靠方法。

值得注意的是,目前的ECMAscript规范中只有short和long被正式定义,其他4个选项只是标准提议的一部分,在撰写本文时,safari中明显没有,尽管它正在进行中

moment.js:

moment().format('zz');

看到这个结果操作符与Timezone相反,所以应用一些数学函数,然后验证num或多或少。

请参见MDN文档 var a = new Date().getTimezoneOffset(); var res = - math .round(a/60)+':'+-(a%60); Res = Res < 0 ? Res: '+'+ Res; console.log (res)