在 JavaScript 中获取另一个时区的时区偏移量,而无需使用字符串

get timezone offset of another timezone in javascript without using Strings

本文关键字:时区 字符串 偏移量 JavaScript 获取 另一个      更新时间:2023-09-26

我想计算从"用户时间"到"湿/西"的偏移量。

我用新Date().getTimezoneOffset()抵消了用户。

但是,如何获得 WET/WEST 的偏移量,以便我可以计算两者的组合偏移量?

例如,如果用户采用中欧时间 (CET/CEST),则在冬季,组合偏移量将为 -60 (CET) + 0 (WET) = -60。在夏季,它将是 -120 (CEST) + 60 (西部) = -60。在这种情况下,它始终为 -60,但用户也可能有一个没有 DST 的时区。

是否可以不将其格式化为字符串并从该字符串中读出新时区?

您不能可靠地使用时区缩写进行输入,因为它们可以用许多不同的方式解释。 例如,CST可能是北美的"中部标准时间",或者"中国标准时间"或"古巴标准时间"。 虽然像WETWEST这样的缩写是独一无二的,但许多缩写是模棱两可的。 请参阅此处的时区缩写列表。

相反,您需要知道 IANA 时区标识符。 使用WET/WEST的一个地点是葡萄牙,它是"Europe/Lisbon"的IANA标识符。 您可以在此处找到标识符列表。 选择正确的标识符很重要,因为时区会随着时间的推移而变化。 每个标识符反映了每个区域的特定历史记录。

如果您知道 IANA 时区标识符,那么您可以选择如何使用它:

  1. 在一些完全支持 ECMAScript 国际化 API (ECMA-402) 时区特性的现代浏览器中,您可以执行以下操作:

    var d = new Date();
    var s = d.toLocaleString(undefined, { timeZone: "Europe/Lisbon" })
    

    这会在格式化过程中将提供的日期和时间转换为正确的时区。 在第一个参数中传递undefined将使用当前区域设置进行格式设置。

    这种方法有一些缺点,因为它尚未在所有浏览器中实现,并且没有用于检索特定时间点的原始时区偏移量的 API。

  2. 您可以考虑使用实现此功能的库。 我在这里列出了其中的几个。 我个人更喜欢时刻.js带有时刻时区插件,您可以执行以下操作:

    var m = moment.tz("Europe/Lisbon");
    var s = m.format();
    

    可以将参数传递给 format 方法,以根据需要显示输出。 您还可以转换现有时间,例如:

    var m = moment.utc("2016-01-01T00:00:00").tz("Europe/Lisbon");
    var s = m.format();
    

    您还可以获取特定时刻的偏移量,如下所示:

    var m = moment.utc("2016-01-01T00:00:00").tz("Europe/Lisbon");
    var offsetInMinutes = m.utcOffset();
    var offsetAsString = m.format("Z");
    
  3. 您可以编写自己的代码来处理特定时区。 虽然这可能容易出错,但我通常不推荐它。 如果您沿着这条路走下去,更新可能会特别困难。

还请记住,特定时区的偏移量将根据生效的日期和时间而有所不同。 因此,表示"现在"的new Date()可能始终是正确的输入,也可能不始终是正确的输入,具体取决于你的方案。

我也想没有库,但即使有时刻,它也有固定数量的时区数据,所以如果你不继续更新,它会在 30 年后中断,只是让我有点恼火。 虽然这确实使用字符串,但没有什么比解析一个只是一个数字的字符串更复杂的了

function getTimezoneOffset(dt, timezone) {
     let getItem = function(format) {
         format.timeZone = timezone;
         return parseInt(dt.toLocaleString(
            'en-US', format));
     };
    
     let adjDate = new Date(
        getItem({year: 'numeric'}),
        getItem({month: 'numeric'}) - 1, // months are zero based
        getItem({day: 'numeric'}),
        getItem({hour: 'numeric',hour12: false}),
        getItem({minute: 'numeric'}));
     let noSecs = new Date(dt.getTime());
     noSecs.setSeconds(0, 0);
     let diff = Math.round((adjDate.getTime() - noSecs.getTime()) / 60000);
    
     return dt.getTimezoneOffset() - diff;
    
}

function getTimezoneOffset(atTime, timeZone) {
    const localizedTime = new Date(atTime.toLocaleString("en-US", {timeZone}));
    const utcTime = new Date(atTime.toLocaleString("en-US", {timeZone: "UTC"}));
    return Math.round((localizedTime.getTime() - utcTime.getTime()) / (60 * 1000));
}
// returns -360 or -420 depending on the time of year 
console.log(getTimezoneOffset(new Date(), "America/Denver"));
// returns -300 or -360 depending on the time of year 
console.log(getTimezoneOffset(new Date(), "America/Chicago"));

我想

在不使用库的情况下做到这一点,所以我写了这个函数,给你给定时区和 UTC 之间的时区偏移量:

function getTimezoneOffsetFrom(otherTimezone) {
    if (otherTimezone === void 0) { otherTimezone = "Europe/Amsterdam"; }
    var date = new Date();
    function objFromStr(str) {
        var array = str.replace(":", " ").split(" ");
        return {
            day: parseInt(array[0]),
            hour: parseInt(array[1]),
            minute: parseInt(array[2])
        };
    }
    var str = date.toLocaleString(['nl-NL'], { timeZone: otherTimezone, day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false });
    var other = objFromStr(str);
    str = date.toLocaleString(['nl-NL'], { day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false });
    var myLocale = objFromStr(str);
    var amsterdamOffset = (other.day * 24 * 60) + (other.hour * 60) + (other.minute);
    var myLocaleOffset = (myLocale.day * 24 * 60) + (myLocale.hour * 60) + (myLocale.minute);
    return myLocaleOffset - amsterdamOffset + date.getTimezoneOffset();
}

也许可以通过使用 en-US 作为区域设置字符串来批准它,然后 str.replace 可能需要过滤逗号或其他东西。