在 JavaScript 中计算给定 TimeZone 字符串的 UTC 偏移量
使用标准 JS 库 (ECMA5),不使用 momentjs 或外部库,如何计算给定 TimeZone 字符串(例如Europe/Rome"或America/Los_Angeles")的 UTC 偏移量?
UTC 偏移量可能取决于它是否是 DST,因此如果解决方案需要将本地客户端日期转换为指定的时区字符串,这将是有意义的.目标只是知道与 UTC 的偏移量.
函数 getUtcOffset(timezone) {//返回整数值.//>0 如果 +GMT//<如果 -GMT 则为 0.}
解决方案ECMAScript中没有函数(ECMA-262) 可以执行您请求的操作.这仅仅是因为标准的 ECMAScript 除了本地计算机和 UTC 之外,对时区一无所知.
但是,在支持 ECMAScript 国际化 API (ECMA-402),并且完全支持 IANA 时区数据库标识符,您可以将这样的函数组合在一起:
function getTimezoneOffset(d, tz) {const a = d.toLocaleString("ja", {timeZone: tz}).split(/[/s:]/);一个[1]——;const t1 = Date.UTC.apply(null, a);const t2 = new Date(d).setMilliseconds(0);返回 (t2 - t1)/60/1000;}
这将适用于当前版本的 Chrome,也许在其他一些地方.但肯定不能保证在任何地方都能工作.特别是,它不能在任何版本的 Internet Explorer 浏览器中运行.
示例用法(在 Chrome 中):
getTimezoneOffset(new Date(2016, 0, 1), "America/New_York")//300getTimezoneOffset(new Date(2016, 6, 1), America/New_York")//240getTimezoneOffset(new Date(2016, 0, 1), "Europe/Paris")//-60getTimezoneOffset(new Date(2016, 6, 1), "Europe/Paris")//-120
关于这个特定功能的一些注意事项:
就像我提到的,它不会在任何地方都有效.最终,所有浏览器都会赶上现代标准,但目前还不会.
你传入的日期确实会影响结果.这是由于夏令时和其他时区异常.您可以只使用
new Date()
传递 current 日期,但结果会根据您调用函数的时间而改变.请参阅时区!= 偏移量";在时区标签wiki中.此函数的结果与
Date.getTimezoneOffset
相同 - 以分钟为单位,正值是 UTC 的 West.如果您使用 ISO8601 偏移量,则需要转换为小时数并反转符号.该函数依赖于
toLocaleString
函数的时区格式化功能.我选择了'ja'
文化,因为日期部分已经按照数组的正确顺序排列.这确实是一个黑客.理想情况下,会有一个 API 可以让您访问时区信息,而无需在格式化时将其绑定到语言环境.不幸的是,这个特定 API 的设计者犯了将时区与语言环境相关联的错误.这是在其他一些不同语言的 API 中犯的错误,不幸的是在这里被带到了 JavaScript 中.明确重申:ECMA-402 中唯一的时区功能是在格式化字符串时应用时区,恕我直言,这是一个设计缺陷.
在我上面的示例使用部分中有一个错误,这说明了为什么这个 API 是错误的部分原因.具体来说,当您创建
Date
对象时,无法指定时区.我传入的 1 月 1 日和 7 月 1 日日期是在 local 时区创建的,而不是在指定的时区.因此,输出可能与您在转换附近的预期不完全一致.这可能会被更多地破解来解决这个问题,但我会把它作为练习留给你.
再次 - 虽然这个答案满足要求的标准,因为没有涉及外部库,我强烈建议 反对 在任何生产代码中使用它.如果您打算为此做任何重要的事情,我会使用我在此处列出的库之一.p>
Using the standard JS library (ECMA5), without using momentjs or external libs, how do you calculate the UTC offset given a TimeZone string such as "Europe/Rome" or "America/Los_Angeles"?
UTC Offsets may depend on whether it is DST or not, so it would make sense if the solution required converting the local client date to the specified Timezone String. The goal is just to know the offset from UTC.
function getUtcOffset(timezone) {
// return int value.
// > 0 if +GMT
// < 0 if -GMT.
}
解决方案
There is no function in ECMAScript (ECMA-262) that can perform the operation you requested. This is simply because standard ECMAScript does not know anything about time zones other than that of the local computer, and UTC.
However, in browsers that support the ECMAScript Internationalization API (ECMA-402), and fully support the IANA time zone database identifiers, you can hack together a function like this:
function getTimezoneOffset(d, tz) {
const a = d.toLocaleString("ja", {timeZone: tz}).split(/[/s:]/);
a[1]--;
const t1 = Date.UTC.apply(null, a);
const t2 = new Date(d).setMilliseconds(0);
return (t2 - t1) / 60 / 1000;
}
This will work in current versions of Chrome, and perhaps in a few other places. but it is certainly not guaranteed to work everywhere. In particular, it won't work in Internet Explorer browsers of any version.
Example usage (in Chrome):
getTimezoneOffset(new Date(2016, 0, 1), "America/New_York") // 300
getTimezoneOffset(new Date(2016, 6, 1), "America/New_York") // 240
getTimezoneOffset(new Date(2016, 0, 1), "Europe/Paris") // -60
getTimezoneOffset(new Date(2016, 6, 1), "Europe/Paris") // -120
A few things to note about this particular function:
Like I mentioned, It's not going to work everywhere. Eventually, as all browsers catch up to modern standards it will, but it won't currently.
The date you pass in will indeed affect the result. This is due daylight saving time and other time zone anomalies. You can pass the current date just with
new Date()
, but the result will change based on when you call the function. See "time zone != offset" in the timezone tag wiki.The results of this function are the same as
Date.getTimezoneOffset
- in terms of minutes, with positive values being West of UTC. If you are working with ISO8601 offsets, you'll need to convert to hours and invert the sign.The function relies on the time zone formatting functionality of the
toLocaleString
function. I picked the'ja'
culture, because the date parts were already in the correct order for the array. This is a hack indeed. Ideally there would be an API that would let you access time zone information without binding it to a locale when formatting. Unfortunately, the designers of this particular API have made the mistake of associating time zone with locale. This is a mistake that's been made in a few other APIs from various languages, and unfortunately was carried into JavaScript here.Restated plainly: The only time zone functionality in ECMA-402 is to apply a time zone when formatting a string, which is a design flaw, IMHO.
There's a bug in my example usage section above, that exemplifies part of why this API is a mistake. Specifically, there's no way to specify a time zone when you create a
Date
object. The Jan 1st and July 1st dates I pass in are created in the local time zone, not in the time zone specified. Therefore, the output may not be exactly what you expect near a transition. This could be hacked even more to work around this problem, but I will leave that as an exercise to you.
Again - Though this answer satisfies the criteria asked for, as there are no external libraries involved, I strongly recommend against using this in any production code. If you're planning on doing anything important with this, I'd use one of the libraries I listed here.
相关文章