使用标准JS库(ECMA5),而不使用momentjs或外部库,如何在给定TimeZone字符串的情况下计算UTC偏移量,例如"欧洲/罗马"或者" America / Los_Angeles"?
UTC偏移量可能取决于它是否为DST,因此如果解决方案需要将本地客户端日期转换为指定的时区字符串,则有意义。目标只是知道UTC的偏移量。
function getUtcOffset(timezone) {
// return int value.
// > 0 if +GMT
// < 0 if -GMT.
}
答案 0 :(得分:6)
你看过时刻时区吗?
moment.tz("America/Los_Angeles").utcOffset();
答案 1 :(得分:3)
ECMAScript(ECMA-262)中没有可以执行您请求的操作的功能。这只是因为标准ECMAScript对本地计算机和UTC以外的时区一无所知。
但是,在支持ECMAScript国际化API(ECMA-402)且完全支持IANA时区数据库标识符的浏览器中,您可以将这样的函数组合在一起:
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中):
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()
传递当前日期,但结果将根据您调用该函数的时间而更改。请参阅the timezone tag wiki中的“时区!=偏移量”。
此功能的结果与Date.getTimezoneOffset
相同 - 以分钟为单位,正值为 West UTC。如果您正在处理ISO8601偏移,则需要转换为小时并反转符号。
该函数依赖于toLocaleString
函数的时区格式化功能。我选择了'ja'
文化,因为日期部分已经按照数组的正确顺序。这确实是一个黑客行为。理想情况下,有一个API可以让您访问时区信息,而不会在格式化时将其绑定到区域设置。不幸的是,这个特定API的设计者错误地将时区与区域设置相关联。这是在其他一些来自不同语言的API中所犯的错误,不幸的是,这里的错误被带到了JavaScript中。
明确重申:ECMA-402中唯一的时区功能是在格式化字符串时应用时区,这是一个设计缺陷,恕我直言。
上面的示例用法部分中存在一个错误,它举例说明了此API错误的部分原因。具体而言,当您创建 Date
对象时,无法指定时区。我传入的1月1日和7月1日日期是在本地时区创建的,而不是在指定的时区中创建的。因此,输出可能与转换附近的预期不完全相同。为了解决这个问题,可能会被黑客攻击,但我会将其作为练习留给您。
再次 - 虽然这个答案满足要求的标准,因为没有涉及外部库,我强烈建议反对在任何生产代码中使用它。如果您计划对此做一些重要的事情,我会使用one of the libraries I listed here。我的个人偏好是moment.js和moment-timezone插件,因为我帮助维护该库。 YMMV
答案 2 :(得分:1)
您必须:
例如以小时为单位的返回时区:
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
答案 3 :(得分:1)
选择的答案并没有真正回答问题。作者想要的是一个可以输入时区名称然后返回偏移量的函数。
经过调查和digging the source code of icu4c,事实证明以下代码片段可以满足您的需求:
const getUtcOffset = (timeZone) => {
const timeZoneName = Intl.DateTimeFormat("ia", {
timeZoneName: "short",
timeZone,
})
.formatToParts()
.find((i) => i.type === "timeZoneName").value;
const offset = timeZoneName.slice(3);
if (!offset) return 0;
const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
if (!matchData) throw `cannot parse timezone name: ${timeZoneName}`;
const [, sign, hour, minute] = matchData;
let result = parseInt(hour) * 60;
if (sign === "-") result *= -1;
if (minute) result + parseInt(minute);
return result;
};
console.log(getUtcOffset("US/Eastern"));
console.log(getUtcOffset("Atlantic/Reykjavik"));
console.log(getUtcOffset("Asia/Tokyo"));
请注意,此处使用的语言环境ia
为Interlingua。原因是根据icu4c的源代码,时区名称因地区而异。即使您使用相同的语言环境,时区名称的格式仍会根据不同的时区而有所不同。
使用Interlingua(ia
)时,格式始终与GMT+NN:NN
相同,可以很容易地对其进行解析。
有点麻烦,但在我自己的产品中效果很好。
希望它也对您有帮助:)
答案 4 :(得分:0)
对于其他可能会遇到此问题的人,JavaScript的标准Date函数上有一种方法可以从UTC获取偏移量,称为getTimezoneOffset。
用法很简单(例如):new Date()。getTimezoneOffset()。这将返回当前时区来自UTC的分钟数。注意:如果当前时区早于UTC,它将返回一个负数。例如,如果用户的时区为UTC + 1,则返回-60。