如何计算 JavaScript 中两个时区的时差?

新手上路,请多包涵

例如,东部和中部的差异是 1。我下面的解决方案感觉很老套。有没有更简单/更好的方法?

 var diff = (parseInt(moment().tz("America/New_York").format("ZZ")) - parseInt(moment().tz("America/Chicago").format("ZZ"))) / 100;

我的例子是使用 Momentjs 库。

原文由 Homer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

计算两个任意时区之间 差异是不可能的。您只能及时计算 特定时刻 的差异。

  • 目前 伦敦和纽约之间有 4 小时的时差(写于 2015 年 3 月 25 日)。
  • 但几周前是 5 个小时的时差,几周后就是 5 个小时了。
  • 每个时区在不同的时间点切换夏令时的偏移量。

这在两个时区之间的一般情况下是正确的。然而, 有些 时区要么完全同时切换,要么根本不切换。

  • 伦敦和巴黎之间 总是相差 一小时,因为它们会在同一时间切换。
  • 亚利桑那州和夏威夷之间 总是 有 3 个小时的时差,因为两者都没有夏令时。

请记住,在美国,每个使用 DST 的时区实际上会在不同的时间切换。它们都在 当地时间 凌晨 2:00 切换,但不是在同一个 通用 时间。

  • 所以芝加哥和纽约之间 通常 相隔1小时
  • 但每年有两个短暂的时期,它们要么相隔 2 小时,要么具有 相同的确切时间。

另请参阅 时区标签 wiki 中的“时区!=偏移量”。

现在关于时刻时区,你在评论中说:

Web 服务器位于东部时区;我们在中环。我需要用户时区和服务器的差异。

Web 服务器的时区无关紧要。您应该能够在世界任何地方进行托管,而不会影响您的应用程序。如果你做不到,那你就做错了。

可以获得 您所在 时区(美国中部时间)与用户所在时区之间的 当前 时差。如果代码在浏览器中运行,您甚至不需要为此知道用户的确切时区:

 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 时区支持的环境中, 无需 Moment 即可完成此操作。这是当今大多数浏览器。

 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

如果你想要它们之间的差异,你可以简单地减去结果。

节点.js

上面的函数在 Node.js 中工作,其中安装了 full-icu 国际化 支持(这是 Node 13 和更新版本的默认设置)。如果您的旧版本带有 system-icusmall-icu ,则可以使用此修改后的函数。它也适用于浏览器和 full-icu 环境,但更大一些。 (我已经在 Linux 上的 Node 8.17.0 和 Windows 上的 Node 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 才能正确应用时区。

原文由 Matt Johnson-Pint 发布,翻译遵循 CC BY-SA 4.0 许可协议

由于夏令时 ( dst ) 之类的原因,两个时区之间的差异只能根据特定时间来衡量。

但是,对于特定日期,下面的代码应该有效。

 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);
}

偏移量/差异以毫秒为单位

那么你所要做的就是:

 const offset = getOffsetBetweenTimezonesForDate(date, 'America/New_York', 'America/Chicago');

原文由 shub_shah 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题