【问题标题】:Get utc offset from timezone in Javascript在Javascript中获取时区的UTC偏移量
【发布时间】:2014-01-09 20:02:25
【问题描述】:

我需要一个给定时区的 Javascript 函数,返回当前的 utc 偏移量。

例如,theFuncIneed('US/Eastern') -> 240

有什么想法吗?

谢谢

【问题讨论】:

  • 创建一个以时区名称为属性、偏移量为值的对象。请注意,时区名称没有标准,它们会不时更改并且存在重复(例如 EST)。
  • 查看moment.js,它有一个zone()方法。
  • @MattJohnson——我不确定你的意思是什么。 IANA 为特定位置提供时区偏移。 IANA 数据不是标准,甚至不是权威数据,也没有任何伪装(数据文件的标题说“此数据绝不是权威数据;如果您认为自己知道得更多,请继续编辑文件”) .
  • @RobG - 同意。 IANA 时区数据库不是 ISO 8601 标准的标准。但按照惯例,它是一个事实上的标准,它在多个操作系统、编程语言和库中普遍使用。因此,尽管没有保证,但US/Eastern 仍然很有可能被所有实现识别。
  • @MattJohnson——我认为这偏离了轨道。我的意思是提醒时区指示符没有标准。 IANA 数据库包含许多例外情况,即某个地方观察到的时区与其地理位置相比,以及夏令时的开始和结束时间与“官方”日期相反。

标签: javascript timezone datejs


【解决方案1】:

@ranjan_purbey 的答案对我来说是NaN,@Weihang Jian 的答案在 Chrome 中抛出异常(但在 Firefox 中有效)。

因此,基于所有答案,我想出了以下功能,它基本上是两个答案的组合,对我来说成功地协同工作:

const getTimeZoneOffset(timeZone) {
    const date = new Date().toLocaleString('en', {timeZone, timeZoneName: 'short'}).split(' ');
    const timeZoneName = date[date.length - 1];
    const offset = timeZoneName.slice(3);
    if (!offset) {
      return 0;
    }
    const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
    if (!matchData) {
      throw new Error(`Cannot parse timezone name: ${timeZoneName}`);
    }
    const [, sign, hour, minute] = matchData;
    let result = parseInt(hour, 10) * 60;
    if (sign === '+') {
      result *= -1;
    }
    if (minute) {
      result += parseInt(minute, 10);
    }
    return result;
}

【讨论】:

  • 我没有得到纽约的时区偏移量,它只是说 EDT (vs UTC-4 or GMT-5)
【解决方案2】:

现在Intl API 已经成为可能:

Intl 的实现基于icu4c。如果你挖掘源代码,你会发现时区名称因地区而异,例如:

for (const locale of ["ja", "en", "fr"]) {
  const timeZoneName = Intl.DateTimeFormat(locale, {
    timeZoneName: "short",
    timeZone: "Asia/Tokyo",
  })
    .formatToParts()
    .find((i) => i.type === "timeZoneName").value;
  console.log(timeZoneName);
}

幸运的是,有一个语言环境Interlingua(语言标记为ia),它使用相同的模式(例如GMT+11:00)作为时区名称。

下面的sn-p可以满足你的需要:

const getOffset = (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(getOffset("US/Eastern")); // 240
console.log(getOffset("Atlantic/Reykjavik")); // 0
console.log(getOffset("Asia/Tokyo")); // -540

这种方式可能有点棘手,但在我的生产项目中效果很好。希望对你也有帮助:)

更新

非常感谢 Bort 指出错字。我已经更正了 sn-p。

【讨论】:

  • if (minute) result + parseInt(minute); 有一个错字。应该是+=
  • 这也不考虑夏令时的变化。
  • 这不适用于示例中的值 - 为“美国/东部”和“大西洋/雷克雅未克”返回 0
  • @Avraham 这会为getOffset("Atlantic/Reykjavik") 返回0,因为这是该时区与UTC 的当前偏移量。对于getOffset("US/Eastern"),它返回240,而不是0
  • @kleinfreund 奇怪,当我运行第二个代码 sn-p 时,我得到 0 for console.log(getOffset("US/Eastern"));
【解决方案3】:

以下函数可用于返回给定时区的 UTC 偏移量:

const getTimezoneOffset = (timeZone, date = new Date()) => {
  const tz = date.toLocaleString("en", {timeZone, timeStyle: "long"}).split(" ").slice(-1)[0];
  const dateString = date.toString();
  const offset = Date.parse(`${dateString} UTC`) - Date.parse(`${dateString} ${tz}`);
  
  // return UTC offset in millis
  return offset;
}

可以这样使用:

const offset = getTimezoneOffset("Europe/London");
console.log(offset);
// expected output => 3600000

【讨论】:

  • 这有点不正确。 UTC 偏移量对于它后面的时区应该是正数,对于它前面的时区应该是负数。因此,减法需要反转:Date.parse(`${dateString} ${tz}`) - Date.parse(`${dateString} UTC`);。否则,它不会与内置的Date.prototype.getTimezoneOffset 对齐。
  • 另外,"Europe/London" 的预期输出应该是 0
  • @Avraham 偏移量取决于夏令时的日期。这就是函数将日期作为第二个参数的原因
  • timeStyle 无效。应该是timeZoneName
  • 我的结果是NaN
【解决方案4】:

您可以使用 moment.js 来做到这一点

moment.tz('时区名称').utcOffset()

虽然这涉及到使用 moment-timezone.js

【讨论】:

  • 你必须也安装了 moment-timezone 包
【解决方案5】:

一般来说,这是不可能的。

  • US/Eastern时区的标识符。 (它实际上是America/New_York 的别名,这是真正的标识符。)

  • 240 是一个时区偏移。更常见的写法是-04:00(反转符号,除以 60)。

  • 美国东部时区由东部标准时间(偏移量为 -05:00)和东部夏令时间(偏移量为 -04:00)组成。

所以说US/Eastern = 240 一点也不准确。请阅读timezone tag wiki,尤其是标题为“时区!=偏移”的部分。

现在您确实要求 当前 偏移量,这 可能的。如果您提供日期+时间参考,则可以解决此问题。

  • 对于执行 javascript 代码的计算机的本地时区,这是使用来自 Date 对象的任何实例的 .getTimeZoneOffset() 内置的。

  • 但如果您希望它用于特定时区,则需要使用one of the libraries I listed here

【讨论】:

  • ECMA-262 将timezone offset 定义为UTC - localTime,以分钟为单位。所以我认为在 javascript 论坛中写 +240 是合理的,否则可能会使用 -04:00
  • .getTimeZoneOffset() 应该是 .getTimezoneOffset() 没有大写 Z
猜你喜欢
  • 1970-01-01
  • 2016-05-07
  • 2013-10-15
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 2011-07-29
相关资源
最近更新 更多