Calculate the UTC offset given a TimeZone string in JavaScript
使用标准JS库(ECMA5),不使用momentjs或外部库,如何在给定TimeZone字符串(如"Europe / Rome"或"America / Los_Angeles")的情况下计算UTC偏移量?
UTC偏移可能取决于它是否为DST,因此如果解决方案需要将本地客户端日期转换为指定的时区字符串,则有意义。 目标只是知道UTC的偏移量。
1 2 3 4 5 | function getUtcOffset(timezone) { // return int value. // > 0 if +GMT // < 0 if -GMT. } |
ECMAScript(ECMA-262)中没有可以执行您请求的操作的功能。这只是因为标准ECMAScript对本地计算机和UTC之外的时区一无所知。
但是,在支持ECMAScript国际化API(ECMA-402)并完全支持IANA时区数据库标识符的浏览器中,您可以将这样的函数组合在一起:
1 2 3 4 5 6 7 | function getTimezoneOffset(d, tz) { var a = d.toLocaleString("ja", {timeZone: tz}).split(/[\/\s:]/); a[1]--; var t1 = Date.UTC.apply(null, a); var t2 = new Date(d).setMilliseconds(0); return (t2 - t1) / 60 / 1000; } |
这适用于当前版本的Chrome,也许还可以在其他一些地方使用。但它无疑保证无处不在。特别是,它不适用于任何版本的Internet Explorer浏览器。
用法示例(在Chrome中):
1 2 3 4 | 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 |
有关此特定功能的一些注意事项:
-
就像我提到的那样,它无处不在。最终,由于所有浏览器都会达到现代标准,但目前还不会。
-
传入的日期确实会影响结果。这是由于夏令时和其他时区异常造成的。您可以使用
new Date() 传递当前日期,但结果将根据您调用函数的时间而更改。请参阅timezone标记wiki中的"time zone!= offset"。 -
此函数的结果与
Date.getTimezoneOffset 相同 - 以分钟为单位,正值为UTC的西。如果您正在使用ISO8601偏移,则需要转换为小时并反转符号。 -
该函数依赖于
toLocaleString 函数的时区格式化功能。我选择了'ja' 文化,因为日期部分已经按照数组的正确顺序。这确实是一个黑客行为。理想情况下,有一个API可以让您访问时区信息,而不会在格式化时将其绑定到区域设置。不幸的是,这个特定API的设计者错误地将时区与区域设置相关联。这是来自各种语言的一些其他API所犯的错误,不幸的是这里被带入了JavaScript。明确重申:ECMA-402中唯一的时区功能是在格式化字符串时应用时区,这是一个设计缺陷,恕我直言。
-
我上面的示例用法部分中有一个错误,它举例说明了此API错误的部分原因。特别是,在创建
Date 对象时无法指定时区。我传入的1月1日和7月1日日期是在本地时区创建的,而不是在指定的时区中创建的。因此,输出可能与转换附近的预期不完全相同。为了解决这个问题,可能会被黑客攻击,但我会将其作为练习留给您。
再次 - 虽然这个答案满足要求的标准,因为没有涉及外部库,我强烈建议不要在任何生产代码中使用它。如果你打算做一些重要的事情,我会使用我在这里列出的一个库。我的个人偏好是moment.js与moment-timezone插件,因为我帮助维护该库。因人而异
你查看了时刻时区吗?
1 | moment.tz("America/Los_Angeles").utcOffset(); |
你必须:
- 获取当前日期时间(将为您提供当前设备当前时区的日期时间)
- 获取当前时区偏移量
- 将日期时间转换为新/所需时区
- 获取当前日期时间和转换后的日期时间之间的差异
- 将所述差异添加到当前时区偏移量
例如,以小时为单位返回时区:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function getTimezoneOffset(tz, hereDate) { hereDate = new Date(hereDate || Date.now()); hereDate.setMilliseconds(0); // for nice rounding const hereOffsetHrs = hereDate.getTimezoneOffset() / 60 * -1, thereLocaleStr = hereDate.toLocaleString('en-US', {timeZone: tz}), thereDate = new Date(thereLocaleStr), diffHrs = (thereDate.getTime() - hereDate.getTime()) / 1000 / 60 / 60, thereOffsetHrs = hereOffsetHrs + diffHrs; console.log(tz, thereDate, 'UTC'+(thereOffsetHrs < 0 ? '' : '+')+thereOffsetHrs); return thereOffsetHrs; } getTimezoneOffset('America/New_York', new Date(2016, 0, 1)); getTimezoneOffset('America/New_York', new Date(2016, 6, 1)); getTimezoneOffset('Europe/Paris', new Date(2016, 0, 1)); getTimezoneOffset('Europe/Paris', new Date(2016, 6, 1)); getTimezoneOffset('Australia/Sydney', new Date(2016, 0, 1)); getTimezoneOffset('Australia/Sydney', new Date(2016, 6, 1)); getTimezoneOffset('Australia/Sydney'); getTimezoneOffset('Australia/Adelaide'); |
哪个输出像
1 2 3 4 5 6 7 8 | America/New_York 2015-12-30T22:00:00.000Z UTC-5 America/New_York 2016-06-30T01:00:00.000Z UTC-4 Europe/Paris 2015-12-31T04:00:00.000Z UTC+1 Europe/Paris 2016-06-30T07:00:00.000Z UTC+2 Australia/Sydney 2015-12-31T14:00:00.000Z UTC+11 Australia/Sydney 2016-06-30T15:00:00.000Z UTC+10 Australia/Sydney 2019-08-14T03:04:21.000Z UTC+10 Australia/Adelaide 2019-08-14T02:34:21.000Z UTC+9.5 |
对于可能出现在这个问题上的其他人,JavaScript中的标准Date函数有一种方法可以获得UTC的偏移,称为getTimezoneOffset。
用法很简单(例如):new Date()。getTimezoneOffset()。这将返回当前时区与UTC的分钟数。注意:如果当前时区早于UTC,则返回负数。例如,如果用户的时区是UTC + 1,则返回-60。