如何计算 JavaScript 中 2 个时区的时差?
How Do I calculate the difference of 2 time zones in JavaScript?
例如,东部和中部的差异是 1。我下面的解决方案感觉很老套。有没有更简单/更好的方法?
var diff = (parseInt(moment().tz("America/New_York").format("ZZ")) - parseInt(moment().tz("America/Chicago").format("ZZ"))) / 100;
我的示例使用的是 Momentjs 库。
计算两个任意时区之间的差异是不可能的。您只能计算特定时刻 的差异 。
- 伦敦和纽约目前时差 4 小时(写于 2015 年 3 月 25 日)。
- 但是几周前是5个小时的时差,几周后就是5个小时了。
- 每个时区在不同的时间点切换夏令时偏移量。
这在两个时区之间的一般情况下是正确的。但是 一些 时区要么完全同时切换,要么根本不切换。
- 伦敦和巴黎之间总是 一个小时,因为它们在同一时刻切换。
- 亚利桑那州和夏威夷之间 总是 3 小时,因为两者都没有夏令时。
请记住,在美国,每个使用 DST 的时区实际上会在不同的时间切换。他们都在 本地 时间的 2:00 上午切换,但不是在相同的 通用 时刻切换。
- 所以芝加哥和纽约之间通常相隔1小时
- 但是每年有两个短暂的时期,它们要么相隔 2 小时,要么具有 相同的确切时间。
另请参阅 the timezone tag wiki 中的“时区 != 偏移量”。
现在关于时刻时区,您在评论中说:
The web server is in the Eastern time zone; we're in Central. I need the difference in the user's timezone and the server.
网络服务器的时区无关紧要。您应该能够在世界任何地方进行托管,而不会影响您的应用程序。如果你做不到,那你就做错了。
您可以获取当前与您的时区(美国中部时间)之间的时差) 和用户的。你甚至不需要为此知道用户的确切时区,如果代码在浏览器中是 运行:
var now = moment();
var localOffset = now.utcOffset();
now.tz("America/Chicago"); // your time zone, not necessarily the server's
var centralOffset = now.utcOffset();
var diffInMinutes = localOffset - centralOffset;
如果服务器上的代码是 运行(在 node.js 应用程序中),那么您 将 需要知道用户的时区。只需像这样更改第一行:
var now = moment.tz("America/New_York"); // their time zone
更新后的答案:
在支持 ECMAScript 国际化 API 并已完全实现 IANA 时区支持的环境中,无需 时刻即可完成此操作。这是当今大多数浏览器。
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
let iso = date.toLocaleString('en-CA', { timeZone, hour12: false }).replace(', ', 'T');
// Include the milliseconds from the original timestamp
iso += '.' + date.getMilliseconds().toString().padStart(3, '0');
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
用法示例:
getTimeZoneOffset(new Date(2020, 3, 13), 'America/New_York') //=> 240
getTimeZoneOffset(new Date(2020, 3, 13), 'Asia/Shanghai') //=> -480
如果你想要它们之间的差异,你可以简单地减去结果。
Node.js
上述功能适用于 Node.js,其中安装了 full-icu
internationalization 支持(这是 Node 13 及更新版本的默认设置)。如果您的旧版本带有 system-icu
或 small-icu
,则可以使用此修改后的函数。它也可以在浏览器和 full-icu
环境中工作,但有点大。 (我已经在 Linux 上的节点 8.17.0 和 Windows 上的节点 12.13.1 上测试了这个。)
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
const options = {timeZone, calendar: 'iso8601', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false};
const dateTimeFormat = new Intl.DateTimeFormat(undefined, options);
const parts = dateTimeFormat.formatToParts(date);
const map = new Map(parts.map(x => [x.type, x.value]));
const year = map.get('year');
const month = map.get('month');
const day = map.get('day');
const hour = `${map.get('hour') % 24}`.padStart(2, "0"); // Sometimes hour value comes as 24
const minute = map.get('minute');
const second = map.get('second');
const ms = date.getMilliseconds().toString().padStart(3, '0');
const iso = `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}`;
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
请注意,无论哪种方式,我们都必须通过Intl
才能正确应用时区。
由于夏令时 (dst) 之类的原因,只能测量 w.r.t 特定时间的两个时区之间的差异。
但是,对于特定日期,下面的代码应该有效。
function getOffsetBetweenTimezonesForDate(date, timezone1, timezone2) {
const timezone1Date = convertDateToAnotherTimeZone(date, timezone1);
const timezone2Date = convertDateToAnotherTimeZone(date, timezone2);
return timezone1Date.getTime() - timezone2Date.getTime();
}
function convertDateToAnotherTimeZone(date, timezone) {
const dateString = date.toLocaleString('en-US', {
timeZone: timezone
});
return new Date(dateString);
}
offset/difference 以毫秒为单位
那么您所要做的就是:
const offset = getOffsetBetweenTimezonesForDate(date, 'America/New_York', 'America/Chicago');
一种使用 toLocaleString 获取时区与 GMT 差异的简单方法。那么你只需要减去即可。
var d = new Date();
var a = d.toLocaleString("en-US", { timeZone: 'Asia/Tokyo', timeZoneName: "short" }).split(/GMT/g)[1];
var b = d.toLocaleString("en-US", { timeZone: 'America/Montreal', timeZoneName: "short" }).split(/GMT/g)[1];
var diff = a - b;
例如,东部和中部的差异是 1。我下面的解决方案感觉很老套。有没有更简单/更好的方法?
var diff = (parseInt(moment().tz("America/New_York").format("ZZ")) - parseInt(moment().tz("America/Chicago").format("ZZ"))) / 100;
我的示例使用的是 Momentjs 库。
计算两个任意时区之间的差异是不可能的。您只能计算特定时刻 的差异 。
- 伦敦和纽约目前时差 4 小时(写于 2015 年 3 月 25 日)。
- 但是几周前是5个小时的时差,几周后就是5个小时了。
- 每个时区在不同的时间点切换夏令时偏移量。
这在两个时区之间的一般情况下是正确的。但是 一些 时区要么完全同时切换,要么根本不切换。
- 伦敦和巴黎之间总是 一个小时,因为它们在同一时刻切换。
- 亚利桑那州和夏威夷之间 总是 3 小时,因为两者都没有夏令时。
请记住,在美国,每个使用 DST 的时区实际上会在不同的时间切换。他们都在 本地 时间的 2:00 上午切换,但不是在相同的 通用 时刻切换。
- 所以芝加哥和纽约之间通常相隔1小时
- 但是每年有两个短暂的时期,它们要么相隔 2 小时,要么具有 相同的确切时间。
另请参阅 the timezone tag wiki 中的“时区 != 偏移量”。
现在关于时刻时区,您在评论中说:
The web server is in the Eastern time zone; we're in Central. I need the difference in the user's timezone and the server.
网络服务器的时区无关紧要。您应该能够在世界任何地方进行托管,而不会影响您的应用程序。如果你做不到,那你就做错了。
您可以获取当前与您的时区(美国中部时间)之间的时差) 和用户的。你甚至不需要为此知道用户的确切时区,如果代码在浏览器中是 运行:
var now = moment();
var localOffset = now.utcOffset();
now.tz("America/Chicago"); // your time zone, not necessarily the server's
var centralOffset = now.utcOffset();
var diffInMinutes = localOffset - centralOffset;
如果服务器上的代码是 运行(在 node.js 应用程序中),那么您 将 需要知道用户的时区。只需像这样更改第一行:
var now = moment.tz("America/New_York"); // their time zone
更新后的答案:
在支持 ECMAScript 国际化 API 并已完全实现 IANA 时区支持的环境中,无需 时刻即可完成此操作。这是当今大多数浏览器。
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
let iso = date.toLocaleString('en-CA', { timeZone, hour12: false }).replace(', ', 'T');
// Include the milliseconds from the original timestamp
iso += '.' + date.getMilliseconds().toString().padStart(3, '0');
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
用法示例:
getTimeZoneOffset(new Date(2020, 3, 13), 'America/New_York') //=> 240
getTimeZoneOffset(new Date(2020, 3, 13), 'Asia/Shanghai') //=> -480
如果你想要它们之间的差异,你可以简单地减去结果。
Node.js
上述功能适用于 Node.js,其中安装了 full-icu
internationalization 支持(这是 Node 13 及更新版本的默认设置)。如果您的旧版本带有 system-icu
或 small-icu
,则可以使用此修改后的函数。它也可以在浏览器和 full-icu
环境中工作,但有点大。 (我已经在 Linux 上的节点 8.17.0 和 Windows 上的节点 12.13.1 上测试了这个。)
function getTimeZoneOffset(date, timeZone) {
// Abuse the Intl API to get a local ISO 8601 string for a given time zone.
const options = {timeZone, calendar: 'iso8601', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false};
const dateTimeFormat = new Intl.DateTimeFormat(undefined, options);
const parts = dateTimeFormat.formatToParts(date);
const map = new Map(parts.map(x => [x.type, x.value]));
const year = map.get('year');
const month = map.get('month');
const day = map.get('day');
const hour = `${map.get('hour') % 24}`.padStart(2, "0"); // Sometimes hour value comes as 24
const minute = map.get('minute');
const second = map.get('second');
const ms = date.getMilliseconds().toString().padStart(3, '0');
const iso = `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}`;
// Lie to the Date object constructor that it's a UTC time.
const lie = new Date(iso + 'Z');
// Return the difference in timestamps, as minutes
// Positive values are West of GMT, opposite of ISO 8601
// this matches the output of `Date.getTimeZoneOffset`
return -(lie - date) / 60 / 1000;
}
请注意,无论哪种方式,我们都必须通过Intl
才能正确应用时区。
由于夏令时 (dst) 之类的原因,只能测量 w.r.t 特定时间的两个时区之间的差异。
但是,对于特定日期,下面的代码应该有效。
function getOffsetBetweenTimezonesForDate(date, timezone1, timezone2) {
const timezone1Date = convertDateToAnotherTimeZone(date, timezone1);
const timezone2Date = convertDateToAnotherTimeZone(date, timezone2);
return timezone1Date.getTime() - timezone2Date.getTime();
}
function convertDateToAnotherTimeZone(date, timezone) {
const dateString = date.toLocaleString('en-US', {
timeZone: timezone
});
return new Date(dateString);
}
offset/difference 以毫秒为单位
那么您所要做的就是:
const offset = getOffsetBetweenTimezonesForDate(date, 'America/New_York', 'America/Chicago');
一种使用 toLocaleString 获取时区与 GMT 差异的简单方法。那么你只需要减去即可。
var d = new Date();
var a = d.toLocaleString("en-US", { timeZone: 'Asia/Tokyo', timeZoneName: "short" }).split(/GMT/g)[1];
var b = d.toLocaleString("en-US", { timeZone: 'America/Montreal', timeZoneName: "short" }).split(/GMT/g)[1];
var diff = a - b;