在 JavaScript 中获取客户端的时区(和偏移量)

IT技术 javascript timezone
2021-02-02 00:53:06

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

我需要两个:

  1. 时区(例如,欧洲/伦敦)
  2. 以及与 UTC 或 GMT 的偏移量(例如,UTC+01)
6个回答

使用偏移量来计算时区是一种错误的方法,你总会遇到问题。时区和夏令时规则在一年中可能会多次更改,并且很难跟上变化。

在 JavaScript 中获取系统的IANA 时区,您应该使用

console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)

截至 2019 年 9 月,这适用于全球 95% 的浏览器

旧的兼容性信息

ecma-402/1.0 表示timeZone如果未提供给构造函数,则可能未定义。但是,未来的草案 (3.0) 通过更改为系统默认时区来解决该问题。

在此版本的 ECMAScript 国际化 API 中,timeZone如果timeZone提供给Intl.DateTimeFormat 构造函数的选项对象中未提供任何属性,则该 属性将保持未定义状态但是,应用程序不应依赖于此,因为未来的版本可能会返回一个字符串值来标识主机环境的当前时区。

在仍处于草案中的 ecma-402/3.0 中,它已更改为

在此版本的 ECMAScript 2015 国际化 API 中,timeZone如果timeZone提供给Intl.DateTimeFormat构造函数的选项对象中未提供任何属性 ,则该 属性将是默认时区的名称 timeZone在这种情况下,以前的版本未定义属性。

验证这现在似乎在 Safari 中工作。(使用版本 10.0)
2021-03-18 00:53:06
这是获取时区的唯一答案,某些用户可能需要时区而不是仅偏移量。因此,作为 2016-09 的更新,Intl 适用于大多数现代浏览器,但不适用于 Safari。对于那个浏览器,这里有一个相当准确的 javascript 回退 - pelepim.bitbucket.org/jstz
2021-03-20 00:53:06
我现在已经在 Chrome 58、Edge 40 和 Firefox 53 上进行了测试 - 它适用于所有这些。它不适用于 IE 11,我没有测试 Opera。
2021-03-26 00:53:06
我花了一段时间才找到这个 API 返回的时区列表。这是:en.wikipedia.org/wiki/List_of_tz_database_time_zones
2021-03-26 00:53:06
如果这适用于所有现代浏览器,那就太好了。但是,IE11 和最新的 Firefox 都为 timeZone 属性返回 undefined。
2021-03-28 00:53:06

使用 getTimezoneOffset()

您可以像这样以分钟为单位获得时区偏移量

var offset = new Date().getTimezoneOffset();
console.log(offset);
// if offset equals -60 then the time zone offset is UTC+01

时区偏移量是 UTC 和本地时间之间的差异(以分钟为单位)。请注意,这意味着如果本地时区落后于 UTC,则偏移量为正,如果领先则为负。例如,如果您的时区是 UTC+10(澳大利亚东部标准时间),则返回 -600。即使对于给定的语言环境,夏令时也会阻止此值保持不变

请注意,并非所有时区都按整小时偏移:例如,纽芬兰是 UTC 减去 3 小时 30 米(将夏令时排除在等式之外)。

另请注意,这只会为您提供时区偏移量(例如:UTC+01),而不会为您提供时区(例如:欧洲/伦敦)。

timezone != utc offset
2021-03-14 00:53:06
好像不考虑夏令时
2021-03-17 00:53:06
@abernier 关于getTimezoneOffset不准确的声明是否有效?您所指的这篇文章的日期为 2007 年 6 月,并且没有详细说明该函数是如何不准确的。事实上,jsTimezoneDetect你指出的图书馆使用getTimezoneOffset自己。
2021-03-21 00:53:06
Intl.DateTimeFormat().resolvedOptions().timeZone 将给出 cient 的时区。
2021-04-04 00:53:06
var hrs = -(new Date().getTimezoneOffset() / 60) 以通常使用的小时数来抵消
2021-04-08 00:53:06

我意识到这个答案有点离题,但我想我们中的许多人在寻找答案时也想格式化时区以进行显示,并且可能也获得时区缩写。所以就到这里了……

如果您希望客户端时区格式良好,您可以依赖 JavaScript Date.toString 方法并执行以下操作:

var split = new Date().toString().split(" ");
var timeZoneFormatted = split[split.length - 2] + " " + split[split.length - 1];

例如,这将为您提供“GMT-0400 (EST)”,包括适用的时区分钟数。

或者,您可以使用正则表达式提取任何所需的部分:

对于“GMT-0400 (EDT)”:

new Date().toString().match(/([A-Z]+[\+-][0-9]+.*)/)[1]

对于“GMT-0400”:

new Date().toString().match(/([A-Z]+[\+-][0-9]+)/)[1]

对于仅“EDT”:

new Date().toString().match(/\(([A-Za-z\s].*)\)/)[1]

对于仅“-0400”:

new Date().toString().match(/([-\+][0-9]+)\s/)[1]

Date.toString 参考:https : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toString

编辑 10/6/2020 - 上述解决方案可能不适用于所有浏览器和语言环境。如果在您的场景中可能,我建议您使用提供时区支持的 javascript 库,如 date-fns、luxon 或 dayjs。

我结束了: var fullTz = new Date().toString().match(/\(([A-Za-z\s].*)\)/)[1]; var parts = fullTz.split(' '); var tz = ""; parts.forEach(function (element, index, array) { tz += element.substring(0, 1); }); 产量:“EST”,例如
2021-03-12 00:53:06
这实际上不是一个好主意,您执行后 JS 时间的实际表示new Date().toString()完全取决于您的语言环境设置。期望其他客户的输出与您的相似是一个非常糟糕的主意。
2021-03-15 00:53:06
这也不适用于(惊喜,惊喜)IE。我刚刚做了一个拆分日期对象的控制台转储。它在 Chrome、Firefox 和 Safari 中相同,但在 IE 中不同。因此,您也不能指望常量索引。2013 年 12 月 2 日星期一 10:22:50 GMT-0500 (EST):Chrome、FF、Safari;2013 年 12 月 2 日星期一 10:22:50 EST:IE10
2021-03-20 00:53:06
因 Chrome 附加时区名称而损坏。不要使用 split.length 而是使用常量split[4] + " " + split[5]?!
2021-03-25 00:53:06
天哪谢谢你!我一直在尝试显示浏览器时区..... ew Date().toString().match(/([AZ]+[\+-][0-9]+.*)/)[ 1] 正是我所需要的!
2021-04-02 00:53:06

已经回答了如何以整数形式在分钟内获得偏移量,但如果有人想要本地 GMT 偏移量作为字符串,例如"+1130"

function pad(number, length){
    var str = "" + number
    while (str.length < length) {
        str = '0'+str
    }
    return str
}

var offset = new Date().getTimezoneOffset()
offset = ((offset<0? '+':'-')+ // Note the reversed sign!
          pad(parseInt(Math.abs(offset/60)), 2)+
          pad(Math.abs(offset%60), 2))
你需要用 1st padding 来替换pad(parseInt(Math.abs(offset/60)), 2)它以使其正确......否则你最终可能会像我一样得到 +5.530......我不确定数学地板等在这里是否会更好......但是这个至少按预期给了我 +0530
2021-03-13 00:53:06
这将给出正确的结果: this.pad(Math.floor((Math.abs(offset/60))), 2)
2021-03-19 00:53:06
替换parseInt(...)(...)|0Math.floor(...)为什么要将其转换为字符串,然后再转换回数字?
2021-03-21 00:53:06
而不是使用你的 pad 函数,我发现这样做更容易: offset = (offset<0 ? "+" : "-") + ("0000" + parseInt((Math.abs(offset/60)))) .切片(-4)
2021-04-01 00:53:06
正是我一直在寻找的。谢谢 !
2021-04-06 00:53:06

您可以使用:

时区

<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
这应该是公认的答案。这是唯一给出实际时区名称而不是偏移量的方法。请记住,时区偏移可以从名称派生,反之则不然。由于 DST 和其他微妙之处,多个时区只能在一年中的某些特定日期具有相同的偏移量。
2021-03-17 00:53:06
现在有一个本地解决方案 - Intl API虽然当时 moment.js 是一个很棒的库,但目前还有更小的替代品(dayjsdate- fns)。瞬间是巨大的请不要将其推荐用于客户端应用程序。
2021-03-26 00:53:06