javascript - 尝试开发 Chrome 扩展以自由更改 TimeZone,但它不起作用
问题描述
我正在开发 chrome 扩展。我想更改 Chrome 网页的时区,但我不能。
我的代码用于覆盖网页 javascript 日期对象。当我将此代码(web-accessible-resources)放在页面上下文中时,页面的时区更改为“Etc/Greenwich”。
我想自由设置保存在 chrome-storage 中的参数并更改页面时区,但我不知道该怎么做。
谁能给我一些建议?
网络可访问资源
(function (o) {
const convertToGMT = function (n) {
const format = function (v) {return (v < 10 ? '0' : '') + v};
return (n <= 0 ? '+' : '-') + format(Math.abs(n) / 60 | 0) + format(Math.abs(n) % 60);
};
//
const resolvedOptions = Intl.DateTimeFormat().resolvedOptions();
const {
toJSON, getYear, getMonth, getHours, toString, getMinutes, getSeconds, getUTCMonth, getFullYear, getUTCHours,
getUTCFullYear, getMilliseconds, getTimezoneOffset, getUTCMilliseconds, toLocaleTimeString, toLocaleDateString,
toISOString, toGMTString, toUTCString, toTimeString, toDateString, getUTCSeconds, getUTCMinutes, toLocaleString,
getDay, getUTCDate, getUTCDay, getDate
} = Date.prototype;
//
Object.defineProperty(Date.prototype, '_offset', {'configurable': true, get() {return getTimezoneOffset.call(this)}});
Object.defineProperty(Date.prototype, '_date', {'configurable': true, get() {
return this._nd !== undefined ? this._nd : new Date(this.getTime() + (this._offset - o.value) * 60 * 1000);
}});
//
Object.defineProperty(Date.prototype, 'toJSON', {"value": function () {return toJSON.call(this._date)}});
Object.defineProperty(Date.prototype, 'getDay', {"value": function () {return getDay.call(this._date)}});
Object.defineProperty(Date.prototype, 'getDate', {"value": function () {return getDate.call(this._date)}});
Object.defineProperty(Date.prototype, 'getYear', {"value": function () {return getYear.call(this._date)}});
Object.defineProperty(Date.prototype, 'getTimezoneOffset', {"value": function () {return Number(o.value)}});
Object.defineProperty(Date.prototype, 'getMonth', {"value": function () {return getMonth.call(this._date)}});
Object.defineProperty(Date.prototype, 'getHours', {"value": function () {return getHours.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCDay', {"value": function () {return getUTCDay.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCDate', {"value": function () {return getUTCDate.call(this._date)}});
Object.defineProperty(Date.prototype, 'getMinutes', {"value": function () {return getMinutes.call(this._date)}});
Object.defineProperty(Date.prototype, 'getSeconds', {"value": function () {return getSeconds.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCMonth', {"value": function () {return getUTCMonth.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCHours', {"value": function () {return getUTCHours.call(this._date)}});
Object.defineProperty(Date.prototype, 'getFullYear', {"value": function () {return getFullYear.call(this._date)}});
Object.defineProperty(Date.prototype, 'toISOString', {"value": function () {return toISOString.call(this._date)}});
Object.defineProperty(Date.prototype, 'toGMTString', {"value": function () {return toGMTString.call(this._date)}});
Object.defineProperty(Date.prototype, 'toUTCString', {"value": function () {return toUTCString.call(this._date)}});
Object.defineProperty(Date.prototype, 'toDateString', {"value": function () {return toDateString.call(this._date)}});
Object.defineProperty(Date.prototype, 'toTimeString', {"value": function () {return toTimeString.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCSeconds', {"value": function () {return getUTCSeconds.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCMinutes', {"value": function () {return getUTCMinutes.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCFullYear', {"value": function () {return getUTCFullYear.call(this._date)}});
Object.defineProperty(Date.prototype, 'toLocaleString', {"value": function () {return toLocaleString.call(this._date)}});
Object.defineProperty(Date.prototype, 'getMilliseconds', {"value": function () {return getMilliseconds.call(this._date)}});
Object.defineProperty(Date.prototype, 'getUTCMilliseconds', {"value": function () {return getUTCMilliseconds.call(this._date)}});
Object.defineProperty(Date.prototype, 'toLocaleTimeString', {"value": function () {return toLocaleTimeString.call(this._date)}});
Object.defineProperty(Date.prototype, 'toLocaleDateString', {"value": function () {return toLocaleDateString.call(this._date)}});
//
Object.defineProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', {"value": function () {return Object.assign(resolvedOptions, {"timeZone": o.name})}});
Object.defineProperty(Date.prototype, 'toString', {'value': function () {
return toString.call(this._date).replace(convertToGMT(this._offset), convertToGMT(o.value)).replace(/\(.*\)/, '(' + o.name.replace(/\//g, ' ') + ' Standard Time)');
}});
//
document.documentElement.dataset.ctzscriptallow = true;
})({'name':'Etc/Greenwich','value':0})
内容脚本
let s = document.createElement('script');
s.src = chrome.runtime.getURL('change-timezone.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
解决方案
谁能给我一些建议?
是的,我可以: 这很难。
使用 Chrome 扩展来更改时区的想法是一个很好的想法。我个人会喜欢这个扩展。然而,这并不是一项微不足道的努力。您需要编写的代码量远远超过 StackOverflow 问题的容量。我建议你开始一个 GitHub 项目并寻找合作者。您可能能够就特定问题获得有关 StackOverflow 的帮助,但不太可能针对整个项目。它太宽泛了。
在您的代码中,您执行此操作的位置:
new Date(this.getTime() + (this._offset - o.value) * 60 * 1000)
这看起来像是试图更改时区,但重要的是你要明白它没有。相反,它所做的是更改嵌入在日期对象中的时间戳。这不会改变时区,它会设置不同的时间点。
这种方法被称为“Epoch Shifting”,它被 Moment.js 等库内部使用。他们可以使用这种技术是因为三件事:
- 移位的
Date
对象仅在内部使用,从不直接暴露给最终用户。 - 一旦对象被移动,就永远不会使用移动对象上的基于本地时间的函数
Date
(例如getHours
或)。toString
仅使用基于 UTC 的函数(例如getUTCHours
或toISOString
)。 - 选择移位的偏移量是转换后的偏移量,而不是之前的偏移量。这变得复杂,但在过渡附近很重要。单元测试可以揭示这里的挑战。
- 移位的
Epoch Shifting 通常作为时区问题的解决方案提出,但是当考虑
Date
对象如何工作时,这是幼稚的。首先,请记住,Date
对象中的时间戳总是在外部和Date
对象中的其他函数中解释为 UTC。此外,Date
对象使用的本地时区直接来自底层本机代码(通常通过特定于操作系统的函数),不会暴露给 JavaScript 进行修改。换句话说,没有 JavaScript 代码可以更改
Date
对象使用的时区。仅当满足上述所有三点时,Epoch Shifting 才是有效的方法。通常应在用户代码中避免使用它。除了
Date
对象的功能之外,您还必须找到一种方法来覆盖Intl.DateTimeFormat
,以便默认解析时区是您正在设置的时区。使用任何方法,您都需要访问时区数据。您可以自带(例如 Moment-Timezone 所做的),或者您可以尝试从 Intl 对象中提取它(例如 Luxon 所做的)。
推荐阅读
- scala - 为多个特征实现重用构造函数
- python-3.x - 使用 Python 3.7.3 在 Raspberry (Buster) 上安装 PyQt5
- python - 任何人都知道一种更有效的方法来对数百条轨迹进行成对比较?
- python - 为什么 dict.get() 不能与设置为默认值的另一个函数一起使用?
- php - url重写缺少参数
- r - R中的经验标准偏差
- sql - VB.NET\Query - COUNT / GROUP BY QUERY 产生不同的结果
- git - 使 gitlab 存储库只读/授予成员访客权限
- python - Python用条件逻辑合并行
- java - 如何在 Javafx 中的某些坐标处将 OnClickListener 设置为背景图像