如何在 JavaScript 中计算 2 个时区的差异?

问题描述 投票:0回答:4

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

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

我的示例是使用 Momentjs 库。

javascript timezone momentjs
4个回答
43
投票

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

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

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

    伦敦和巴黎之间
  • 总是一小时,因为它们在同一时刻转换。
  • 亚利桑那州和夏威夷之间
  • 总是 3 小时,因为两者都没有夏令时。
请记住,在美国,每个使用 DST 的时区实际上会在不同的时间点切换。它们都在

本地时间凌晨 2:00 切换,但不是在同一通用时间。

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

时区标签 wiki 中的“时区 != 偏移量”。

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

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

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

可以获取您的时区(美国中部时间)与用户所在时区之间的当前时差。如果代码在浏览器中运行,您甚至不需要知道用户的确切时区: 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

上述函数适用于安装了

full-icu

国际化
支持的 Node.js(这是 Node 13 及更高版本的默认设置)。如果您的旧版本带有 system-icu
small-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才能正确应用时区。

    


1
投票
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');



0
投票
https://stackoverflow.com/a/29268535/7412781

答案的工作 Typescript 代码 export function getTimeZoneOffset(date: Date, timeZone: string) { // Abuse the Intl API to get a local ISO 8601 string for a given time zone. const isoStrRaw = date .toLocaleString("en-CA", { timeZone, hour12: false }) .replace(", ", "T"); // Convert the MM/dd/YYYY to YYYY-MM-DD const toks = isoStrRaw.split("T"); // Save the string to memory before split again. const token0: string = toks[0]; const toksD = token0.split("/"); const dateStr = toksD[2] + "-" + toksD[0].padStart(2, "0") + "-" + toksD[1].padStart(2, "0"); const iso = dateStr + "T" + toks[1] + "." + 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.getTime() - date.getTime()) / 60 / 1000; }



-1
投票

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;

© www.soinside.com 2019 - 2024. All rights reserved.