GM *_*cid 8 javascript timezone datetime locale offset
使用标准的JS库(ECMA5),而无需使用momentjs或外部库,你如何计算UTC偏移给出一个TimeZone字符串,如"欧洲/罗马"或"美国/洛杉矶"?
UTC偏移可能取决于它是否为DST,因此如果解决方案需要将本地客户端日期转换为指定的时区字符串,则有意义.目标只是知道UTC的偏移量.
function getUtcOffset(timezone) {
// return int value.
// > 0 if +GMT
// < 0 if -GMT.
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*int 10
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;
}
Run Code Online (Sandbox Code Playgroud)
这将在当前版本的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
Run Code Online (Sandbox Code Playgroud)
有关此特定功能的一些注意事项:
就像我提到的那样,它不会在所有地方都起作用。最终,随着所有浏览器都赶上现代标准,它会,但是目前不会。
您传递的日期确实会影响结果。这是由于夏时制和其他时区异常。您可以使用来传递当前日期new Date()
,但是结果将根据调用函数的时间而改变。请参阅时区标记Wiki中的 “时区!=偏移量” 。
Date.getTimezoneOffset
以分钟为单位,此函数的结果与- 相同,正值为UTC的西。如果您使用的是ISO8601偏移量,则需要转换为小时并反转符号。
该功能依赖于该功能的时区格式化toLocaleString
功能。我选择了'ja'
区域性,因为日期部分已经按照数组的正确顺序排列了。这确实是一个hack。理想情况下,将有一个API使您可以在格式化时访问时区信息,而不必将其绑定到语言环境。不幸的是,该特定API的设计者犯了将时区与语言环境相关联的错误。这是其他几种来自多种语言的API所犯的错误,不幸的是,此处已将其带入JavaScript。
明确地说:ECMA-402中唯一的时区功能是在格式化字符串时应用时区,这是设计缺陷,恕我直言。
上面的示例用法部分中有一个错误,该错误说明了此API错误的部分原因。具体而言,有没有办法当你指定一个时间区创建一个Date
对象。我传递的1月1日和7月1日是在本地时区中创建的,而不是在指定的时区中创建的。因此,输出可能不是您在过渡附近所期望的。为了解决此问题,可能会更多地利用它,但是我将作为练习留给您。
再说一次-尽管此答案满足了所要求的标准,但由于不涉及外部库,因此我强烈建议不要在任何生产代码中使用此答案。如果您打算对此做任何重要的事情,那么我将使用这里列出的库之一。我个人比较喜欢带有moment-timezone插件的moment.js,因为我可以帮助维护该库。青年汽车
小智 8
你查看了时刻时区吗?
moment.tz("America/Los_Angeles").utcOffset();
Run Code Online (Sandbox Code Playgroud)
你必须:
例如以小时为单位返回时区:
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');
Run Code Online (Sandbox Code Playgroud)
哪个输出像
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
Run Code Online (Sandbox Code Playgroud)
所选答案并不能真正回答问题。作者想要的是一个可以输入时区名称然后返回偏移量的函数。
经过一番调查并挖掘 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"));
Run Code Online (Sandbox Code Playgroud)
请注意,此处使用的语言环境ia
是Interlingua。原因是根据 icu4c 的源代码,时区名称因语言环境而异。即使您使用相同的区域设置,时区名称的格式仍然会根据不同的时区而有所不同。
使用Interlingua ( ia
),格式始终是相同的模式GMT+NN:NN
,可以轻松解析。
这有点棘手,但在我自己的产品中效果很好。
希望它也能帮助你:)
归档时间: |
|
查看次数: |
5624 次 |
最近记录: |