在JavaScript中计算给定时区字符串的UTC偏移量
使用标准JS库(ECMA5),在不使用momentjs或外部LIB的情况下,如何计算给定时区字符串(如“欧洲/罗马”或“美国/洛杉矶”)的UTC偏移量 UTC偏移量可能取决于它是否为DST,因此,如果解决方案需要将本地客户端日期转换为指定的时区字符串,那么它是有意义的。目标只是知道UTC的偏移量在JavaScript中计算给定时区字符串的UTC偏移量,javascript,datetime,timezone,locale,offset,Javascript,Datetime,Timezone,Locale,Offset,使用标准JS库(ECMA5),在不使用momentjs或外部LIB的情况下,如何计算给定时区字符串(如“欧洲/罗马”或“美国/洛杉矶”)的UTC偏移量 UTC偏移量可能取决于它是否为DST,因此,如果解决方案需要将本地客户端日期转换为指定的时区字符串,那么它是有意义的。目标只是知道UTC的偏移量 function getUtcOffset(timezone) { // return int value. // > 0 if +GMT // < 0 if -GMT. }
function getUtcOffset(timezone) {
// return int value.
// > 0 if +GMT
// < 0 if -GMT.
}
函数getUtcOffset(时区){
//返回int值。
//如果+GMT,则大于0
//<0如果-GMT。
}
你检查过时刻时区了吗
moment.tz("America/Los_Angeles").utcOffset();
ECMAScript()中没有可以执行您请求的操作的函数。这仅仅是因为标准ECMAScript除了本地计算机和UTC之外,对时区一无所知 但是,在支持ECMAScript国际化API()并完全支持IANA时区数据库标识符的浏览器中,您可以组合如下函数:
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;
}
这将在当前的Chrome版本中起作用,也许在其他一些地方也会起作用。但它肯定不能保证在任何地方都能起作用。特别是,它在任何版本的Internet Explorer浏览器中都不起作用
示例用法(在Chrome中):
关于此特定函数,需要注意以下几点:
- 就像我提到的,它不会在任何地方都起作用。最终,随着所有浏览器赶上现代标准,它会的,但目前不会
- 你输入的日期确实会影响结果。这是由于夏令时和其他时区异常。只需使用
,即可传递当前日期,但结果将根据调用函数的时间而变化。请参见中的“时区!=偏移”new date()
- 此函数的结果与
相同,以分钟为单位,正值位于UTC以西。如果使用ISO8601偏移,则需要转换为小时并反转符号Date.getTimezoneOffset
- 该函数依赖于
函数的时区格式化功能。我选择了toLocaleString
区域性,因为日期部分已经按照数组的正确顺序排列。这确实是一种黑客行为。理想情况下,应该有一个API,允许您在格式化时访问时区信息,而无需将其绑定到区域设置。不幸的是,这个特定API的设计者犯了将时区与区域设置相关联的错误。这是来自不同语言的一些其他API中所犯的错误,不幸的是,它被带入了JavaScript中 简单重申:ECMA-402中唯一的时区功能是在格式化字符串时应用时区,这是一个设计缺陷,IMHO。'ja'
- 在我上面的示例使用部分中有一个bug,它举例说明了为什么这个API是一个错误。具体来说,在创建
对象时,无法指定时区。我传入的1月1日和7月1日日期是在本地时区中创建的,而不是在指定的时区中创建的。因此,在转换附近,输出可能与您期望的不完全相同。为了解决这个问题,可以对它进行更多的黑客攻击,但我将把它作为练习留给你们Date
同样-尽管这个答案满足要求的标准,因为没有涉及外部库,但我强烈建议不要在任何生产代码中使用它。如果您打算对此做一些重要的事情,我会使用。对于其他可能涉及此问题的人,JavaScript中的标准日期函数中提供了一种方法,用于获取UTC的偏移量,称为getTimezoneOffset 用法很简单(例如):new Date().getTimezoneOffset()。返回当前时区距UTC的分钟数。注意:如果当前时区早于UTC,则返回负数。例如,如果用户的时区为UTC+1,则返回-60。您必须:
- 获取当前日期时间(将提供当前设备当前时区中的日期时间)
- 获取当前时区偏移量
- 将日期时间转换为新的/所需的时区
- 获取当前日期时间和转换的日期时间之间的差异
- 将所述差异添加到当前时区偏移
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');
选择的答案并不能真正回答问题。作者想要的是一个可以输入时区名称然后返回偏移量的函数 经过一些调查和分析,以下代码片段可以满足您的需要:
const getUtcOffset=(时区)=>{
常量timeZoneName=Intl.DateTimeFormat(“ia”{
时区名称:“短”,
时区,
})
.formatToParts()
.find((i)=>i.type==“timeZoneName”).value;
常量偏移=时区名称切片(3);
如果(!offset)返回0;
常量matchData=offset.match(/([+-])(\d+(:(\d+)))/;
如果(!matchData)throw`无法分析时区名称:${timeZoneName}`;
常数[,符号,小时,分钟]=匹配数据;
设结果=parseInt(小时)*60;
如果(符号==“-”)结果*=-1;
if(分钟)结果+parseInt(分钟);
返回结果;
};
控制台日志(getUtcOffset(“美国/东部”);
console.log(getUtcOffset(“大西洋/雷克雅未克”);
console.log(getUtcOffset(“亚洲/东京”)这是一个很好的答案,但事实证明我毕竟不能使用momentjs。我一直在使用一个非常旧的版本,它有parseZone,但没有.tz。旧的momentjs根本没有时区全名的查找表。因此,如果可能的话,我需要一种在原生JS中实现这一点的方法。.tz
数据在插件中单独提供。谢谢@MattJohnson。但是,我不希望添加时刻时区。我不完全拥有这个软件,所以更改libs不是一件容易的事。谢谢,但是有
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');
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